@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.
Files changed (168) hide show
  1. package/.eslintrc.cjs +79 -0
  2. package/.gitattributes +2 -0
  3. package/.github/workflows/chromatic.yml +28 -0
  4. package/.github/workflows/publish-storybook.yml +41 -0
  5. package/.husky/pre-commit +4 -0
  6. package/.prettierrc.cjs +10 -0
  7. package/.storybook/Theme.js +17 -0
  8. package/.storybook/main.ts +20 -0
  9. package/.storybook/manager-head.html +3 -0
  10. package/.storybook/manager.js +8 -0
  11. package/.storybook/preview-head.html +3 -0
  12. package/.storybook/preview.ts +36 -0
  13. package/.storybook/source-panel/manager.js +28 -0
  14. package/.storybook/withSource.js +91 -0
  15. package/.vscode/extensions.json +11 -0
  16. package/.vscode/settings.json +20 -0
  17. package/index.html +13 -0
  18. package/lib/main.ts +48 -0
  19. package/package.json +2 -8
  20. package/postcss.config.cjs +9 -0
  21. package/resources/rocket-ui-logo-dark.svg +27 -0
  22. package/resources/rocket-ui-logo-light.svg +27 -0
  23. package/shims-rocketui.d.ts +9 -0
  24. package/src/App.vue +15 -0
  25. package/src/assets/blank-avatar.svg +3 -0
  26. package/src/assets/icons/mdi.js +7302 -0
  27. package/src/assets/logo.svg +1 -0
  28. package/src/components/Accordion/Accordion.mdx +88 -0
  29. package/src/components/Accordion/Accordion.stories.ts +257 -0
  30. package/src/components/Accordion/RAccordion.vue +73 -0
  31. package/src/components/Accordion/accordion.css +75 -0
  32. package/src/components/Accordion/accordion.spec.ts +123 -0
  33. package/src/components/Alert/Alert.mdx +120 -0
  34. package/src/components/Alert/Alert.stories.ts +118 -0
  35. package/src/components/Alert/RAlert.vue +119 -0
  36. package/src/components/Alert/alert.css +136 -0
  37. package/src/components/Alert/alert.spec.ts +32 -0
  38. package/src/components/Avatar/Avatar.mdx +96 -0
  39. package/src/components/Avatar/Avatar.stories.ts +65 -0
  40. package/src/components/Avatar/RAvatar.vue +115 -0
  41. package/src/components/Avatar/avatar.css +82 -0
  42. package/src/components/Avatar/avatar.spec.ts +38 -0
  43. package/src/components/Badge/Badge.mdx +112 -0
  44. package/src/components/Badge/Badge.stories.ts +99 -0
  45. package/src/components/Badge/RBadge.vue +89 -0
  46. package/src/components/Badge/badge.css +63 -0
  47. package/src/components/Badge/badge.spec.ts +20 -0
  48. package/src/components/Box/Box.mdx +20 -0
  49. package/src/components/Box/Box.stories.ts +56 -0
  50. package/src/components/Box/RBox.vue +97 -0
  51. package/src/components/Breadcrumb/Breadcrumb.stories.ts +115 -0
  52. package/src/components/Breadcrumb/RBreadcrumb.vue +43 -0
  53. package/src/components/Breadcrumb/breadcrumb.css +29 -0
  54. package/src/components/Button/Button.mdx +148 -0
  55. package/src/components/Button/Button.spec.ts +29 -0
  56. package/src/components/Button/Button.stories.ts +118 -0
  57. package/src/components/Button/RButton.vue +179 -0
  58. package/src/components/Button/button.css +146 -0
  59. package/src/components/Checkbox/Checkbox.mdx +100 -0
  60. package/src/components/Checkbox/Checkbox.stories.ts +67 -0
  61. package/src/components/Checkbox/RCheckbox.vue +195 -0
  62. package/src/components/Checkbox/checkbox.css +67 -0
  63. package/src/components/Checkbox/checkbox.spec.ts +60 -0
  64. package/src/components/Chips/Chip.mdx +113 -0
  65. package/src/components/Chips/Chip.stories.ts +122 -0
  66. package/src/components/Chips/RChip.vue +125 -0
  67. package/src/components/Chips/chip.css +62 -0
  68. package/src/components/Chips/chip.spec.ts +40 -0
  69. package/src/components/Dropdown/Dropdown.mdx +135 -0
  70. package/src/components/Dropdown/Dropdown.stories.ts +84 -0
  71. package/src/components/Dropdown/RDropdown.vue +392 -0
  72. package/src/components/Dropdown/dropdown.css +113 -0
  73. package/src/components/Dropdown/dropdown.spec.ts +98 -0
  74. package/src/components/Flex/Flex.mdx +20 -0
  75. package/src/components/Flex/Flex.stories.js +127 -0
  76. package/src/components/Flex/RFlex.vue +91 -0
  77. package/src/components/Grid/Grid.mdx +20 -0
  78. package/src/components/Grid/Grid.stories.js +107 -0
  79. package/src/components/Grid/RGrid.vue +138 -0
  80. package/src/components/Icon/Icon.mdx +68 -0
  81. package/src/components/Icon/Icon.stories.ts +33 -0
  82. package/src/components/Icon/RIcon.vue +56 -0
  83. package/src/components/Icon/icon.spec.ts +25 -0
  84. package/src/components/ItemGroup/ItemGroup.stories.ts +91 -0
  85. package/src/components/ItemGroup/RItem.vue +74 -0
  86. package/src/components/ItemGroup/RItemGroup.vue +122 -0
  87. package/src/components/ItemGroup/__snapshots__/itemgroup.spec.ts.snap +13 -0
  88. package/src/components/ItemGroup/itemgroup.spec.ts +67 -0
  89. package/src/components/Label/Label.mdx +50 -0
  90. package/src/components/Label/Label.stories.ts +38 -0
  91. package/src/components/Label/RLabel.vue +42 -0
  92. package/src/components/Label/label.css +0 -0
  93. package/src/components/Modal/Modal.mdx +91 -0
  94. package/src/components/Modal/Modal.stories.ts +125 -0
  95. package/src/components/Modal/RModal.vue +130 -0
  96. package/src/components/Modal/modal.css +41 -0
  97. package/src/components/Modal/modal.spec.ts +25 -0
  98. package/src/components/Pagination/Pagination.stories.ts +24 -0
  99. package/src/components/Pagination/RPagination.vue +103 -0
  100. package/src/components/Pagination/pagination.css +47 -0
  101. package/src/components/Pagination/pagination.spec.ts +17 -0
  102. package/src/components/ProgressBar/ProgressBar.stories.ts +34 -0
  103. package/src/components/ProgressBar/RProgressBar.vue +21 -0
  104. package/src/components/ProgressBar/progressbar.css +24 -0
  105. package/src/components/ProgressBar/progressbar.spec.ts +17 -0
  106. package/src/components/Shared/Enums.ts +1 -0
  107. package/src/components/Sidebar/RSidebar.vue +27 -0
  108. package/src/components/Sidebar/Sidebar.mdx +31 -0
  109. package/src/components/Sidebar/Sidebar.stories.ts +34 -0
  110. package/src/components/Sidebar/sidebar.css +18 -0
  111. package/src/components/Sidebar/sidebar.spec.ts +33 -0
  112. package/src/components/Snackbar/RSnackbar.vue +136 -0
  113. package/src/components/Snackbar/Snackbar.mdx +126 -0
  114. package/src/components/Snackbar/Snackbar.stories.ts +93 -0
  115. package/src/components/Snackbar/snackbar.css +99 -0
  116. package/src/components/Snackbar/snackbar.spec.ts +56 -0
  117. package/src/components/Switch/RSwitch.vue +147 -0
  118. package/src/components/Switch/Switch.mdx +102 -0
  119. package/src/components/Switch/Switch.stories.ts +79 -0
  120. package/src/components/Switch/switch.css +102 -0
  121. package/src/components/Switch/switch.spec.ts +31 -0
  122. package/src/components/TabItem/RTabItem.vue +175 -0
  123. package/src/components/TabItem/TabItem.mdx +95 -0
  124. package/src/components/TabItem/TabItem.spec.ts +29 -0
  125. package/src/components/TabItem/TabItem.stories.ts +97 -0
  126. package/src/components/TabItem/common.ts +6 -0
  127. package/src/components/TabItem/tab-item.css +29 -0
  128. package/src/components/Tabs/RTabs.vue +94 -0
  129. package/src/components/Tabs/Tabs.mdx +78 -0
  130. package/src/components/Tabs/Tabs.spec.ts +28 -0
  131. package/src/components/Tabs/Tabs.stories.ts +191 -0
  132. package/src/components/Tabs/tabs.css +13 -0
  133. package/src/components/Tabs/types.ts +11 -0
  134. package/src/components/TextArea/RTextArea.vue +142 -0
  135. package/src/components/TextArea/TextArea.mdx +108 -0
  136. package/src/components/TextArea/TextArea.stories.ts +55 -0
  137. package/src/components/TextArea/textarea.css +51 -0
  138. package/src/components/TextArea/textarea.spec.ts +36 -0
  139. package/src/components/Textfield/RTextfield.vue +372 -0
  140. package/src/components/Textfield/Textfield.mdx +159 -0
  141. package/src/components/Textfield/Textfield.stories.ts +121 -0
  142. package/src/components/Textfield/textfield.css +81 -0
  143. package/src/components/Textfield/textfield.spec.ts +34 -0
  144. package/src/components/Tooltip/RTooltip.vue +325 -0
  145. package/src/components/Tooltip/Tooltip.mdx +111 -0
  146. package/src/components/Tooltip/Tooltip.stories.ts +203 -0
  147. package/src/components/Tooltip/common.ts +91 -0
  148. package/src/components/Tooltip/tooltip.css +34 -0
  149. package/src/components/Tooltip/tooltip.spec.ts +81 -0
  150. package/src/components/Typography/Typography.mdx +109 -0
  151. package/src/components/Typography/typography.css +128 -0
  152. package/src/directives/index.ts +19 -0
  153. package/src/index.css +241 -0
  154. package/src/main.ts +5 -0
  155. package/src/scripts/buildIcons.js +21 -0
  156. package/src/stories/Colors.mdx +355 -0
  157. package/src/stories/GettingStarted.mdx +121 -0
  158. package/src/stories/Layout.mdx +15 -0
  159. package/tailwind.config.cjs +16 -0
  160. package/tsconfig.json +24 -0
  161. package/vite.config.ts +39 -0
  162. package/vitest.config.ts +12 -0
  163. package/dist/rocket-ui-vue.js +0 -9381
  164. package/dist/rocket-ui-vue.umd.cjs +0 -1
  165. package/dist/style.css +0 -2
  166. package/dist/types/main.d.ts +0 -25
  167. /package/{dist → public}/design-tokens.source.json +0 -0
  168. /package/{dist → public}/favicon.ico +0 -0
@@ -0,0 +1,179 @@
1
+ <script setup lang="ts">
2
+ import './button.css';
3
+ import { computed, type CSSProperties } from 'vue';
4
+ import Icon from '../Icon/RIcon.vue';
5
+ export type ButtonType =
6
+ | 'primary'
7
+ | 'secondary'
8
+ | 'text'
9
+ | 'outline'
10
+ | 'ghost'
11
+ | 'link'
12
+ | 'danger';
13
+ export type ButtonSize = 'small' | 'medium' | 'large';
14
+ export interface Props {
15
+ /**
16
+ * Variant of the Button
17
+ * @type 'primary' | 'secondary' | 'text' | 'outline' | 'ghost' | 'link' | 'danger'
18
+ * @default 'primary'
19
+ * @example
20
+ * <Button variant="primary" />
21
+ */
22
+ variant?: ButtonType;
23
+
24
+ /**
25
+ * Loading state of the Button
26
+ * @type boolean
27
+ * @default false
28
+ * @example
29
+ * <Button loading />
30
+ */
31
+ loading?: boolean;
32
+
33
+ /**
34
+ * Disabled state of the Button
35
+ * @type boolean
36
+ * @default false
37
+ * @example
38
+ * <Button disabled />
39
+ */
40
+ disabled?: boolean;
41
+
42
+ /**
43
+ * Prepend icon of the Button
44
+ * @type string
45
+ * @default ''
46
+ * @example
47
+ * <Button prependIcon="icon" />
48
+ */
49
+ prependIcon?: string;
50
+
51
+ /**
52
+ * Append icon of the Button
53
+ * @type string
54
+ * @default ''
55
+ * @example
56
+ * <Button appendIcon="icon" />
57
+ */
58
+ appendIcon?: string;
59
+
60
+ /**
61
+ * Only icon state of the Button
62
+ * @type boolean
63
+ * @default false
64
+ * @example
65
+ * <Button onlyIcon />
66
+ */
67
+ onlyIcon?: boolean;
68
+
69
+ /**
70
+ * Size of the Button
71
+ * @type 'small' | 'medium' | 'large'
72
+ * @default 'medium'
73
+ * @example
74
+ * <Button size="small" />
75
+ */
76
+ size?: ButtonSize;
77
+
78
+ /**
79
+ * Height of the Button
80
+ * @type string
81
+ * @default ''
82
+ * @example
83
+ * <Button height="40" />
84
+ */
85
+ height?: string;
86
+
87
+ /**
88
+ * Block state of the Button
89
+ * @type boolean
90
+ * @default false
91
+ * @example
92
+ * <Button block />
93
+ * @link https://tailwindcss.com/docs/display#block
94
+ */
95
+ block?: boolean;
96
+
97
+ /**
98
+ * Background color of the Button
99
+ * @type CSSProperties['backgroundColor']
100
+ * @default ''
101
+ * @example
102
+ * <Button backgroundColor="red" />
103
+ */
104
+ backgroundColor?: CSSProperties['backgroundColor'];
105
+
106
+ /**
107
+ * Color of the Button
108
+ * @type string
109
+ * @default ''
110
+ * @example
111
+ * <Button color="red" />
112
+ */
113
+ color?: string;
114
+ }
115
+ const props = withDefaults(defineProps<Props>(), {
116
+ variant: 'primary',
117
+ loading: false,
118
+ disabled: false,
119
+ prependIcon: '',
120
+ appendIcon: '',
121
+ onlyIcon: false,
122
+ size: 'medium',
123
+ height: '',
124
+ block: false,
125
+ backgroundColor: '',
126
+ });
127
+ const classes = computed(() => ({
128
+ button: true,
129
+ [`button--${props.variant}`]: true,
130
+ [`button--loading`]: props.loading,
131
+ [`button--${props.size || 'medium'}`]: true,
132
+ [`button--only-icon`]: props.onlyIcon,
133
+ [`button--block`]: props.block,
134
+ }));
135
+ defineEmits(['click']);
136
+ const iconSize = computed(() => {
137
+ return {
138
+ small: 20,
139
+ medium: 24,
140
+ large: 32,
141
+ }[props.size || 'medium'];
142
+ });
143
+ const style = computed(() => {
144
+ const { backgroundColor, height, color } = props;
145
+ return {
146
+ backgroundColor,
147
+ height: height ? `${height}px` : '',
148
+ color,
149
+ };
150
+ });
151
+ </script>
152
+ <template>
153
+ <button
154
+ v-bind="$attrs"
155
+ :class="classes"
156
+ :disabled="disabled || loading"
157
+ :style="style"
158
+ @click.stop="$emit('click')"
159
+ >
160
+ <slot name="custom-icon" />
161
+
162
+ <Icon
163
+ v-if="!$slots['custom-icon'] && props.prependIcon"
164
+ :class="{
165
+ 'button__prepend-icon': true,
166
+ 'button__prepend-icon--only': props.onlyIcon,
167
+ }"
168
+ :name="props.prependIcon"
169
+ :size="iconSize"
170
+ />
171
+ <slot v-if="!props.onlyIcon" />
172
+ <Icon
173
+ v-if="!$slots['custom-icon'] && !props.onlyIcon && props.appendIcon"
174
+ class="button__append-icon"
175
+ :name="props.appendIcon"
176
+ :size="iconSize"
177
+ />
178
+ </button>
179
+ </template>
@@ -0,0 +1,146 @@
1
+ @import '../../index.css';
2
+
3
+ .button {
4
+ @apply w-fit antialiased flex items-center justify-center transition-all rounded-[var(--btn-radius)] text-white font-medium cursor-pointer;
5
+
6
+ &:active {
7
+ @apply ring-2 ring-inset;
8
+ animation: manipulation 15s ease-in;
9
+ }
10
+
11
+ &:disabled {
12
+ @apply cursor-not-allowed;
13
+ }
14
+
15
+ &--large {
16
+ @apply h-14 text-base px-6 py-4;
17
+ }
18
+ &--medium {
19
+ @apply h-12 text-sm px-6 py-3;
20
+ }
21
+ &--small {
22
+ @apply h-9 text-xs px-4 py-2;
23
+ }
24
+ &--loading {
25
+ @apply animate-pulse;
26
+
27
+ /* ---Not yet implemented---
28
+ & .button__prepend-icon {
29
+ @apply animate-spin;
30
+ }
31
+ & .button__append-icon {
32
+ @apply animate-spin;
33
+ } */
34
+ }
35
+
36
+ &--large&--only-icon {
37
+ @apply p-[1rem];
38
+ }
39
+ &--medium&--only-icon {
40
+ @apply p-[0.875rem];
41
+ }
42
+ &--small&--only-icon {
43
+ @apply px-4 py-2;
44
+ }
45
+ &--block {
46
+ @apply w-full;
47
+ }
48
+
49
+ &__prepend-icon {
50
+ @apply mr-2;
51
+ &--only {
52
+ @apply mr-0;
53
+ }
54
+ }
55
+ &__append-icon {
56
+ @apply ml-2;
57
+ }
58
+ }
59
+ .button--primary {
60
+ @apply bg-[var(--primary-500)];
61
+
62
+ &:hover {
63
+ @apply bg-[var(--primary-700)];
64
+ }
65
+ &:active {
66
+ @apply ring-[var(--primary-100)] bg-white text-[var(--primary-500)];
67
+ }
68
+ &:disabled {
69
+ @apply bg-[var(--primary-200)] text-[var(--primary-300)];
70
+ }
71
+ }
72
+ .button--secondary {
73
+ @apply bg-[var(--primary-100)] text-[var(--primary-500)];
74
+
75
+ &:hover {
76
+ @apply bg-[var(--primary-200)];
77
+ }
78
+ &:active {
79
+ @apply ring-[var(--primary-100)] bg-white text-[var(--primary-500)];
80
+ }
81
+ &:disabled {
82
+ @apply bg-[var(--primary-200)] text-[var(--primary-300)];
83
+ }
84
+ }
85
+ .button--outline {
86
+ @apply bg-transparent ring-1 ring-[var(--neutral-200)] text-[var(--neutral-900)];
87
+
88
+ &:hover {
89
+ @apply bg-[var(--neutral-100)];
90
+ }
91
+ &:active {
92
+ @apply ring-[var(--neutral-100)] bg-white text-[var(--neutral-900)];
93
+ }
94
+ &:disabled {
95
+ @apply bg-white text-[var(--neutral-300)];
96
+ }
97
+ }
98
+ .button--text {
99
+ @apply text-[var(--neutral-900)] bg-transparent h-auto rounded-none p-0;
100
+
101
+ &:active {
102
+ @apply ring-0 ring-inherit;
103
+ }
104
+ &:disabled {
105
+ @apply bg-white text-[var(--neutral-300)];
106
+ }
107
+ }
108
+ .button--ghost {
109
+ @apply bg-transparent text-[var(--primary-100)];
110
+
111
+ &:hover {
112
+ @apply bg-[var(--neutral-100)] text-[var(--primary-500)];
113
+ }
114
+ &:active {
115
+ @apply ring-[var(--neutral-100)] bg-white text-[var(--neutral-900)];
116
+ }
117
+ &:disabled {
118
+ @apply bg-white text-[var(--neutral-300)];
119
+ }
120
+ }
121
+ .button--danger {
122
+ @apply bg-[var(--error-500)];
123
+
124
+ &:hover {
125
+ @apply bg-[var(--error-700)];
126
+ }
127
+ &:active {
128
+ @apply ring-[var(--error-100)] bg-white text-[var(--error-500)];
129
+ }
130
+ &:disabled {
131
+ @apply bg-[var(--error-200)] text-[var(--error-300)];
132
+ }
133
+ }
134
+ .button--link {
135
+ @apply bg-transparent text-[var(--primary-500)];
136
+
137
+ &:hover {
138
+ @apply bg-[var(--neutral-100)] text-[var(--primary-500)];
139
+ }
140
+ &:active {
141
+ @apply ring-[var(--neutral-100)] bg-white text-[var(--neutral-900)];
142
+ }
143
+ &:disabled {
144
+ @apply bg-white text-[var(--neutral-300)];
145
+ }
146
+ }
@@ -0,0 +1,100 @@
1
+ import { Canvas, Meta, Story, Controls } from '@storybook/blocks';
2
+ import * as CheckboxStories from './Checkbox.stories';
3
+
4
+ <Meta of={CheckboxStories} />
5
+
6
+ # Checkbox
7
+
8
+ A checkbox is a simple UI element that allows the user to select one or more options from a set of predefined choices. It is often used in forms, surveys, and other types of user input scenarios.
9
+
10
+ - [Overview](#overview)
11
+
12
+ - [Playground](#playground)
13
+
14
+ - [Usage with props](#usage)
15
+
16
+ - [Variants](#variants)
17
+
18
+ - [Tips](#tips)
19
+
20
+ ## Overview <a id="overview" />
21
+
22
+ A checkbox is typically represented by a small square box that can be checked (marked) or unchecked (unmarked). Checkbox component typically consists of a label that describes the associated option, and a checkbox input element that allows the user to select or deselect the option. The component may also include additional elements such as a description or further explanation of the option.
23
+
24
+ <Canvas>
25
+ <Story of={CheckboxStories.Overview} />
26
+ </Canvas>
27
+
28
+ ## Playground <a id="playground" />
29
+
30
+ > Changes you make in the controls will be reflected in the example above.
31
+
32
+ <Controls of={CheckboxStories.Overview} exclude={/^(update.*)$/} />
33
+
34
+ ## Usage with props <a id="usage" />
35
+
36
+ ### id (required)
37
+
38
+ The **id** prop is a unique identifier for the checkbox element. This prop is required.
39
+
40
+ ### label (optional)
41
+
42
+ The **label** prop is used to clearly communicate the purpose of the checkbox to the user.
43
+
44
+ ### indeterminate (optional)
45
+
46
+ The **indeterminate** prop is used to represent a state that is partially checked, such as when some but not all options in a group are selected.
47
+
48
+ ### disabled (optional)
49
+
50
+ The **disabled** prop is used to prevent the user from interacting with the checkbox when it is not relevant or applicable.
51
+
52
+ ### modelValue (optional)
53
+
54
+ The **modelValue** prop is used to control the checked state of the checkbox. This can be useful when you want to implement conditional logic or when you want to bind the checkbox to a data model.
55
+
56
+ ### hint (optional)
57
+
58
+ The **hint** prop is used to provide additional information or context to the user. This can be used to clarify the purpose of the checkbox or to provide guidance on how to use it.
59
+
60
+ ### errorMsg (optional)
61
+
62
+ The **errorMsg** prop is used to indicate that the checkbox is required or has an error. This can be used to highlight issues to the user and help them fix them.
63
+
64
+ ### change (optional)
65
+
66
+ The **change** prop is used to handle the checkbox's checked state changes. This function will be passed the new checked state as an argument, which you can use to update your application state or perform other actions.
67
+
68
+ ## Variants <a id="variants" />
69
+
70
+ ### Checked
71
+
72
+ <Canvas>
73
+ <Story of={CheckboxStories.Checked} />
74
+ </Canvas>
75
+
76
+ ### Indeterminate
77
+
78
+ <Canvas>
79
+ <Story of={CheckboxStories.Indeterminate} />
80
+ </Canvas>
81
+
82
+ ### With Error
83
+
84
+ <Canvas>
85
+ <Story of={CheckboxStories.WithError} />
86
+ </Canvas>
87
+
88
+ ## Tips <a id="tips" />
89
+
90
+ 💡 Use clear and concise labels. Make sure that the _label_ for the checkbox accurately and clearly describes the option that it represents. Avoid using jargon or ambiguous terms that may be confusing to the user.
91
+
92
+ 💡 Use _indeterminate_ state appropriately. Use this state sparingly and only when it makes sense in the context of your application.
93
+
94
+ 💡 Use _disabled_ state appropriately. Avoid using this state excessively, as it can make the user feel like they are being restricted or prevented from interacting with the checkbox.
95
+
96
+ 💡 Use the _checked_ prop to control the checked state. This can be useful in scenarios where you want to pre-populate a form with default values, or where you want to update the checked state based on user actions or other conditions.
97
+
98
+ 💡 Use the _hint_ prop to provide additional context. Use this prop sparingly and only when it is necessary to fully explain the purpose or implications of the checkbox.
99
+
100
+ 💡 Use the _errorMsg_ prop to indicate errors. Use this prop to help the user understand that there is a problem with the form and encourage them to correct any errors before submitting.
@@ -0,0 +1,67 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3';
2
+ import Checkbox from './RCheckbox.vue';
3
+
4
+ const DefaultArgs = {
5
+ id: 'checkbox',
6
+ label: 'Checkbox Label',
7
+ indeterminate: false,
8
+ disabled: false,
9
+ hint: 'Save my login details for next time.',
10
+ errorMsg: '',
11
+ modelValue: false,
12
+ };
13
+
14
+ const CheckboxStory = {
15
+ title: 'Form/Checkbox',
16
+ component: Checkbox,
17
+ setup(args: typeof Checkbox) {
18
+ return { args };
19
+ },
20
+ template: '<Checkbox v-bind="args" />',
21
+ args: DefaultArgs,
22
+ argTypes: {
23
+ modelValue: {
24
+ control: {
25
+ type: 'boolean',
26
+ },
27
+ },
28
+ 'onUpdate:modelValue': {
29
+ action: 'update:modelValue',
30
+ },
31
+ },
32
+ } as Meta<typeof Checkbox>;
33
+
34
+ export default CheckboxStory;
35
+
36
+ type Story = StoryObj<typeof CheckboxStory>;
37
+
38
+ export const Overview: Story = {
39
+ args: {
40
+ id: 'checkbox-1',
41
+ label: 'Checkbox label',
42
+ },
43
+ };
44
+
45
+ export const Checked: Story = {
46
+ args: {
47
+ id: 'checkbox-1',
48
+ label: 'Checkbox label',
49
+ modelValue: true,
50
+ },
51
+ };
52
+
53
+ export const Indeterminate: Story = {
54
+ args: {
55
+ id: 'checkbox-1',
56
+ label: 'Checkbox label',
57
+ indeterminate: true,
58
+ },
59
+ };
60
+
61
+ export const WithError: Story = {
62
+ args: {
63
+ id: 'checkbox-1',
64
+ label: 'Checkbox label',
65
+ errorMsg: 'This field is required',
66
+ },
67
+ };
@@ -0,0 +1,195 @@
1
+ <script setup lang="ts">
2
+ import './checkbox.css';
3
+ import {
4
+ computed,
5
+ reactive,
6
+ watch,
7
+ type HTMLAttributes,
8
+ type InputHTMLAttributes,
9
+ type LabelHTMLAttributes,
10
+ } from 'vue';
11
+
12
+ import Icon from '../Icon/RIcon.vue';
13
+ export interface Props {
14
+ /**
15
+ * id of the checkbox
16
+ * @type HTMLAttributes['id']
17
+ * @default ''
18
+ * @example
19
+ * <Checkbox id="checkbox" />
20
+ * @link https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id
21
+ */
22
+ id: HTMLAttributes['id'];
23
+
24
+ /**
25
+ * Input checked state
26
+ * @type InputHTMLAttributes['checked']
27
+ * @default false
28
+ * @example
29
+ * <Checkbox :modelValue="true" />
30
+ * @link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#checked
31
+ */
32
+ modelValue?: InputHTMLAttributes['checked'];
33
+
34
+ /**
35
+ * label of the checkbox
36
+ * @type LabelHTMLAttributes['label']
37
+ * @default ''
38
+ * @example
39
+ * <Checkbox label="Checkbox" />
40
+ * @link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label
41
+ */
42
+ label?: LabelHTMLAttributes['for'];
43
+
44
+ /**
45
+ * Input indeterminate state
46
+ * @type InputHTMLAttributes['indeterminate']
47
+ * @default false
48
+ * @example
49
+ * <Checkbox indeterminate="true" />
50
+ * @link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#indeterminate
51
+ */
52
+ indeterminate?: InputHTMLAttributes['indeterminate'];
53
+
54
+ /**
55
+ * Input disabled state
56
+ * @type InputHTMLAttributes['disabled']
57
+ * @default false
58
+ * @example
59
+ * <Checkbox disabled="true" />
60
+ * @link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#disabled
61
+ */
62
+ disabled?: InputHTMLAttributes['disabled'];
63
+
64
+ /**
65
+ * Hint text
66
+ * @type string
67
+ * @default ''
68
+ * @example
69
+ * <Checkbox hint="This is a hint" />
70
+ */
71
+ hint?: string;
72
+
73
+ /**
74
+ * Error message
75
+ * @type string
76
+ * @default ''
77
+ * @example
78
+ * <Checkbox errorMsg="This is an error" />
79
+ */
80
+ errorMsg?: string;
81
+ }
82
+
83
+ type StateTypes = {
84
+ checked: InputHTMLAttributes['checked'];
85
+ indeterminate: InputHTMLAttributes['indeterminate'];
86
+ };
87
+
88
+ const props = withDefaults(defineProps<Props>(), {
89
+ id: '',
90
+ label: '',
91
+ indeterminate: false,
92
+ disabled: false,
93
+ hint: '',
94
+ errorMsg: '',
95
+ modelValue: false,
96
+ });
97
+
98
+ const emit = defineEmits(['update:modelValue']);
99
+
100
+ const state = reactive<StateTypes>({
101
+ checked: false,
102
+ indeterminate: false,
103
+ });
104
+
105
+ const icons = {
106
+ checked: 'mdiCheck',
107
+ unchecked: '',
108
+ indeterminate: 'mdiMinus',
109
+ };
110
+
111
+ const icon = computed(() => {
112
+ if (state.indeterminate) {
113
+ return icons.indeterminate;
114
+ }
115
+ return state.checked ? icons.checked : icons.unchecked;
116
+ });
117
+
118
+ const classes = computed(() => {
119
+ return {
120
+ checkbox: true,
121
+ 'checkbox--checked': state.checked,
122
+ 'checkbox--disabled': props.disabled,
123
+ 'checkbox--indeterminate': state.indeterminate,
124
+ 'checkbox--error': !!props.errorMsg,
125
+ };
126
+ });
127
+
128
+ const onChange = (e: unknown) => {
129
+ if (props.disabled) return;
130
+ // @ts-expect-error: Unreachable code error
131
+ state.checked = e.target.checked;
132
+ state.indeterminate = false;
133
+ emit('update:modelValue', state.checked);
134
+ };
135
+
136
+ watch(
137
+ () => props.indeterminate,
138
+ (value) => {
139
+ state.indeterminate = value;
140
+ if (value === true) {
141
+ state.checked = false;
142
+ emit('update:modelValue', state.checked);
143
+ }
144
+ },
145
+ {
146
+ // need immediate to set the state on first render for storybook
147
+ // TODO: find a better way to do this
148
+ immediate: true,
149
+ }
150
+ );
151
+ watch(
152
+ () => props.modelValue,
153
+ (value) => {
154
+ state.checked = value;
155
+ },
156
+ {
157
+ // need immediate to set the state on first render for storybook
158
+ // TODO: find a better way to do this
159
+ immediate: true,
160
+ }
161
+ );
162
+ </script>
163
+ <template>
164
+ <div class="checkbox-wrapper">
165
+ <div class="checkbox-container">
166
+ <input
167
+ :id="props.id"
168
+ :checked="state.checked"
169
+ class="checkbox-container__input"
170
+ :disabled="props.disabled"
171
+ :indeterminate="state.indeterminate"
172
+ type="checkbox"
173
+ @change="onChange"
174
+ />
175
+ <div :class="classes" :data-disabled="props.disabled">
176
+ <Icon :name="icon" :size="24" />
177
+ </div>
178
+ </div>
179
+ <div class="checkbox-texts">
180
+ <label
181
+ class="checkbox-texts__label"
182
+ :data-disabled="props.disabled"
183
+ :for="props.id"
184
+ >
185
+ {{ props.label }}
186
+ </label>
187
+ <p v-if="!!props.errorMsg" class="checkbox-texts__error">
188
+ {{ props.errorMsg }}
189
+ </p>
190
+ <p v-else class="checkbox-texts__hint">
191
+ {{ props.hint }}
192
+ </p>
193
+ </div>
194
+ </div>
195
+ </template>