@300codes/design-system 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +155 -0
- package/package.json +63 -0
- package/src/components/BaseIcon/BaseIcon.stories.ts +66 -0
- package/src/components/BaseIcon/BaseIcon.vue +96 -0
- package/src/components/BaseIcon/index.ts +2 -0
- package/src/components/BaseLabel/BaseLabel.stories.ts +114 -0
- package/src/components/BaseLabel/BaseLabel.vue +149 -0
- package/src/components/BaseLabel/index.ts +2 -0
- package/src/components/BaseTooltip/BaseTooltip.stories.ts +113 -0
- package/src/components/BaseTooltip/BaseTooltip.vue +123 -0
- package/src/components/BaseTooltip/index.ts +2 -0
- package/src/components/ButtonWithIcon/ButtonWithIcon.stories.ts +149 -0
- package/src/components/ButtonWithIcon/ButtonWithIcon.vue +77 -0
- package/src/components/ButtonWithIcon/index.ts +2 -0
- package/src/components/CheckboxInput/CheckboxInput.stories.ts +99 -0
- package/src/components/CheckboxInput/CheckboxInput.vue +176 -0
- package/src/components/CheckboxInput/index.ts +2 -0
- package/src/components/LabelInput/LabelInput.vue +111 -0
- package/src/components/LabelInput/index.ts +2 -0
- package/src/components/RadioInput/RadioInput.stories.ts +114 -0
- package/src/components/RadioInput/RadioInput.vue +174 -0
- package/src/components/RadioInput/index.ts +2 -0
- package/src/components/SearchInput/SearchInput.stories.ts +103 -0
- package/src/components/SearchInput/SearchInput.vue +83 -0
- package/src/components/SearchInput/index.ts +2 -0
- package/src/components/SelectInput/SelectInput.stories.ts +111 -0
- package/src/components/SelectInput/SelectInput.vue +497 -0
- package/src/components/SelectInput/index.ts +2 -0
- package/src/components/SelectInputField/SelectInputField.stories.ts +141 -0
- package/src/components/SelectInputField/SelectInputField.vue +64 -0
- package/src/components/SelectInputField/index.ts +2 -0
- package/src/components/SimpleButton/SimpleButton.stories.ts +143 -0
- package/src/components/SimpleButton/SimpleButton.vue +193 -0
- package/src/components/SimpleButton/index.ts +2 -0
- package/src/components/TabsList/TabsList.stories.ts +83 -0
- package/src/components/TabsList/TabsList.vue +156 -0
- package/src/components/TabsList/index.ts +2 -0
- package/src/components/TextInput/TextInput.stories.ts +125 -0
- package/src/components/TextInput/TextInput.vue +273 -0
- package/src/components/TextInput/components/InputIconButton.vue +54 -0
- package/src/components/TextInput/index.ts +2 -0
- package/src/components/TextInputField/TextInputField.stories.ts +133 -0
- package/src/components/TextInputField/TextInputField.vue +93 -0
- package/src/components/TextInputField/index.ts +2 -0
- package/src/components/index.ts +15 -0
- package/src/css/tokens.css +417 -0
- package/src/types/icon.ts +1 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import type { ConcreteComponent } from 'vue';
|
|
3
|
+
import type { BaseTooltipProps } from './BaseTooltip.vue';
|
|
4
|
+
import BaseTooltip from './BaseTooltip.vue';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<BaseTooltipProps> = {
|
|
7
|
+
title: 'Components/BaseTooltip',
|
|
8
|
+
component: BaseTooltip as unknown as ConcreteComponent<BaseTooltipProps>,
|
|
9
|
+
tags: ['autodocs'],
|
|
10
|
+
argTypes: {
|
|
11
|
+
size: {
|
|
12
|
+
control: 'select',
|
|
13
|
+
options: ['md', 'lg'],
|
|
14
|
+
},
|
|
15
|
+
position: {
|
|
16
|
+
control: 'select',
|
|
17
|
+
options: ['bottom', 'left', 'right', 'top'],
|
|
18
|
+
},
|
|
19
|
+
closeSize: {
|
|
20
|
+
control: 'select',
|
|
21
|
+
options: [undefined, '2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', 'auto'],
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default meta;
|
|
27
|
+
type Story = StoryObj<BaseTooltipProps>;
|
|
28
|
+
|
|
29
|
+
export const Default: Story = {
|
|
30
|
+
args: {
|
|
31
|
+
size: 'md',
|
|
32
|
+
position: 'bottom',
|
|
33
|
+
},
|
|
34
|
+
render: (args: BaseTooltipProps) => ({
|
|
35
|
+
components: { BaseTooltip },
|
|
36
|
+
setup() {
|
|
37
|
+
return { args };
|
|
38
|
+
},
|
|
39
|
+
template: '<BaseTooltip v-bind="args">Tooltip text</BaseTooltip>',
|
|
40
|
+
}),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const WithClose: Story = {
|
|
44
|
+
args: {
|
|
45
|
+
size: 'md',
|
|
46
|
+
position: 'bottom',
|
|
47
|
+
closeSize: 'md',
|
|
48
|
+
},
|
|
49
|
+
render: (args: BaseTooltipProps) => ({
|
|
50
|
+
components: { BaseTooltip },
|
|
51
|
+
setup() {
|
|
52
|
+
return { args };
|
|
53
|
+
},
|
|
54
|
+
template: '<BaseTooltip v-bind="args">Tooltip with close button</BaseTooltip>',
|
|
55
|
+
}),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const Large: Story = {
|
|
59
|
+
args: {
|
|
60
|
+
size: 'lg',
|
|
61
|
+
position: 'bottom',
|
|
62
|
+
closeSize: 'md',
|
|
63
|
+
},
|
|
64
|
+
render: (args: BaseTooltipProps) => ({
|
|
65
|
+
components: { BaseTooltip },
|
|
66
|
+
setup() {
|
|
67
|
+
return { args };
|
|
68
|
+
},
|
|
69
|
+
template: '<BaseTooltip v-bind="args">Large tooltip text</BaseTooltip>',
|
|
70
|
+
}),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const PositionTop: Story = {
|
|
74
|
+
args: {
|
|
75
|
+
size: 'md',
|
|
76
|
+
position: 'top',
|
|
77
|
+
},
|
|
78
|
+
render: (args: BaseTooltipProps) => ({
|
|
79
|
+
components: { BaseTooltip },
|
|
80
|
+
setup() {
|
|
81
|
+
return { args };
|
|
82
|
+
},
|
|
83
|
+
template: '<BaseTooltip v-bind="args">Tooltip top</BaseTooltip>',
|
|
84
|
+
}),
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const PositionLeft: Story = {
|
|
88
|
+
args: {
|
|
89
|
+
size: 'md',
|
|
90
|
+
position: 'left',
|
|
91
|
+
},
|
|
92
|
+
render: (args: BaseTooltipProps) => ({
|
|
93
|
+
components: { BaseTooltip },
|
|
94
|
+
setup() {
|
|
95
|
+
return { args };
|
|
96
|
+
},
|
|
97
|
+
template: '<BaseTooltip v-bind="args">Tooltip left</BaseTooltip>',
|
|
98
|
+
}),
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const PositionRight: Story = {
|
|
102
|
+
args: {
|
|
103
|
+
size: 'md',
|
|
104
|
+
position: 'right',
|
|
105
|
+
},
|
|
106
|
+
render: (args: BaseTooltipProps) => ({
|
|
107
|
+
components: { BaseTooltip },
|
|
108
|
+
setup() {
|
|
109
|
+
return { args };
|
|
110
|
+
},
|
|
111
|
+
template: '<BaseTooltip v-bind="args">Tooltip right</BaseTooltip>',
|
|
112
|
+
}),
|
|
113
|
+
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { IconSize } from '../../types/icon';
|
|
3
|
+
import BaseIcon from '../BaseIcon/BaseIcon.vue';
|
|
4
|
+
|
|
5
|
+
export interface BaseTooltipProps {
|
|
6
|
+
size?: 'md' | 'lg';
|
|
7
|
+
position?: 'bottom' | 'left' | 'right' | 'top';
|
|
8
|
+
closeSize?: IconSize;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
withDefaults(defineProps<BaseTooltipProps>(), {
|
|
12
|
+
size: 'md',
|
|
13
|
+
position: 'bottom',
|
|
14
|
+
closeSize: undefined,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const emit = defineEmits<{
|
|
18
|
+
close: [];
|
|
19
|
+
}>();
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<div
|
|
24
|
+
role="tooltip"
|
|
25
|
+
:class="[
|
|
26
|
+
'baseTooltip',
|
|
27
|
+
`baseTooltip--${size}`,
|
|
28
|
+
`baseTooltip--${position}`,
|
|
29
|
+
'relative inline-flex',
|
|
30
|
+
]"
|
|
31
|
+
>
|
|
32
|
+
<div :class="['baseTooltip__body', 'flex items-center']">
|
|
33
|
+
<div class="baseTooltip__text">
|
|
34
|
+
<slot />
|
|
35
|
+
</div>
|
|
36
|
+
<button
|
|
37
|
+
v-if="closeSize"
|
|
38
|
+
:class="[
|
|
39
|
+
'baseTooltip__close',
|
|
40
|
+
'bg-transparent border-0 p-0 cursor-pointer inline-flex items-center justify-center shrink-0',
|
|
41
|
+
]"
|
|
42
|
+
type="button"
|
|
43
|
+
aria-label="Close"
|
|
44
|
+
@click="emit('close')"
|
|
45
|
+
>
|
|
46
|
+
<BaseIcon
|
|
47
|
+
name="close"
|
|
48
|
+
:size="closeSize"
|
|
49
|
+
/>
|
|
50
|
+
</button>
|
|
51
|
+
</div>
|
|
52
|
+
<span
|
|
53
|
+
aria-hidden="true"
|
|
54
|
+
class="baseTooltip__arrow absolute w-0 h-0"
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
</template>
|
|
58
|
+
|
|
59
|
+
<style scoped>
|
|
60
|
+
@reference "tailwindcss";
|
|
61
|
+
|
|
62
|
+
.baseTooltip {
|
|
63
|
+
--_arrow-half-w: var(--baseTooltip-arrow-half-w, 0.375rem);
|
|
64
|
+
--_arrow-h: var(--baseTooltip-arrow-h, 0.5rem);
|
|
65
|
+
|
|
66
|
+
background-color: var(--baseTooltip-bg, #0e161b);
|
|
67
|
+
color: var(--baseTooltip-fg, #ffffff);
|
|
68
|
+
border-radius: var(--baseTooltip-radius, 0.5rem);
|
|
69
|
+
max-width: var(--baseTooltip-max-w, 12.25rem);
|
|
70
|
+
padding: var(--baseTooltip-py, 1rem) var(--baseTooltip-px, 1rem);
|
|
71
|
+
font-size: var(--baseTooltip-font-size, 0.75rem);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.baseTooltip--lg {
|
|
75
|
+
--_arrow-half-w: var(--baseTooltip-lg-arrow-half-w, 0.75rem);
|
|
76
|
+
--_arrow-h: var(--baseTooltip-lg-arrow-h, 1rem);
|
|
77
|
+
|
|
78
|
+
font-size: var(--baseTooltip-lg-font-size, 0.875rem);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.baseTooltip__body {
|
|
82
|
+
gap: var(--baseTooltip-gap, 1rem);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.baseTooltip__close:focus-visible {
|
|
86
|
+
outline: 2px solid var(--baseTooltip-fg, #ffffff);
|
|
87
|
+
|
|
88
|
+
@apply outline-offset-2;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* ── arrow ── */
|
|
92
|
+
|
|
93
|
+
.baseTooltip--bottom .baseTooltip__arrow {
|
|
94
|
+
@apply bottom-0 left-1/2 -translate-x-1/2 translate-y-full;
|
|
95
|
+
border-left: var(--_arrow-half-w) solid transparent;
|
|
96
|
+
border-right: var(--_arrow-half-w) solid transparent;
|
|
97
|
+
border-top: var(--_arrow-h) solid var(--baseTooltip-bg, #0e161b);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.baseTooltip--top .baseTooltip__arrow {
|
|
101
|
+
border-left: var(--_arrow-half-w) solid transparent;
|
|
102
|
+
border-right: var(--_arrow-half-w) solid transparent;
|
|
103
|
+
border-bottom: var(--_arrow-h) solid var(--baseTooltip-bg, #0e161b);
|
|
104
|
+
|
|
105
|
+
@apply top-0 left-1/2 -translate-x-1/2 -translate-y-full;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.baseTooltip--left .baseTooltip__arrow {
|
|
109
|
+
border-top: var(--_arrow-half-w) solid transparent;
|
|
110
|
+
border-bottom: var(--_arrow-half-w) solid transparent;
|
|
111
|
+
border-right: var(--_arrow-h) solid var(--baseTooltip-bg, #0e161b);
|
|
112
|
+
|
|
113
|
+
@apply left-0 top-1/2 -translate-y-1/2 -translate-x-full;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.baseTooltip--right .baseTooltip__arrow {
|
|
117
|
+
border-top: var(--_arrow-half-w) solid transparent;
|
|
118
|
+
border-bottom: var(--_arrow-half-w) solid transparent;
|
|
119
|
+
border-left: var(--_arrow-h) solid var(--baseTooltip-bg, #0e161b);
|
|
120
|
+
|
|
121
|
+
@apply right-0 top-1/2 -translate-y-1/2 translate-x-full;
|
|
122
|
+
}
|
|
123
|
+
</style>
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import type { ConcreteComponent } from 'vue';
|
|
3
|
+
import type { ButtonWithIconProps } from './ButtonWithIcon.vue';
|
|
4
|
+
import ButtonWithIcon from './ButtonWithIcon.vue';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<ButtonWithIconProps> = {
|
|
7
|
+
title: 'Components/ButtonWithIcon',
|
|
8
|
+
component: ButtonWithIcon as unknown as ConcreteComponent<ButtonWithIconProps>,
|
|
9
|
+
tags: ['autodocs'],
|
|
10
|
+
argTypes: {
|
|
11
|
+
variant: {
|
|
12
|
+
control: 'select',
|
|
13
|
+
options: ['primary', 'secondary', 'tertiary'],
|
|
14
|
+
},
|
|
15
|
+
size: {
|
|
16
|
+
control: 'select',
|
|
17
|
+
options: ['sm', 'md'],
|
|
18
|
+
},
|
|
19
|
+
iconPosition: {
|
|
20
|
+
control: 'select',
|
|
21
|
+
options: ['left', 'right'],
|
|
22
|
+
},
|
|
23
|
+
iconSize: {
|
|
24
|
+
control: 'select',
|
|
25
|
+
options: ['2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', 'auto'],
|
|
26
|
+
},
|
|
27
|
+
loading: { control: 'boolean' },
|
|
28
|
+
full: { control: 'boolean' },
|
|
29
|
+
disabled: { control: 'boolean' },
|
|
30
|
+
ariaLabel: { control: 'text' },
|
|
31
|
+
icon: { control: 'text' },
|
|
32
|
+
iconPath: { control: 'text' },
|
|
33
|
+
href: { control: 'text' },
|
|
34
|
+
target: { control: 'text' },
|
|
35
|
+
rel: { control: 'text' },
|
|
36
|
+
type: {
|
|
37
|
+
control: 'select',
|
|
38
|
+
options: ['button', 'submit', 'reset'],
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default meta;
|
|
44
|
+
type Story = StoryObj<ButtonWithIconProps>;
|
|
45
|
+
|
|
46
|
+
export const Primary: Story = {
|
|
47
|
+
args: { variant: 'primary', size: 'md', icon: 'star', iconPosition: 'left' },
|
|
48
|
+
render: (args: ButtonWithIconProps) => ({
|
|
49
|
+
components: { ButtonWithIcon },
|
|
50
|
+
setup() { return { args }; },
|
|
51
|
+
template: '<ButtonWithIcon v-bind="args">Button label</ButtonWithIcon>',
|
|
52
|
+
}),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const Secondary: Story = {
|
|
56
|
+
args: { variant: 'secondary', size: 'md', icon: 'star', iconPosition: 'left' },
|
|
57
|
+
render: (args: ButtonWithIconProps) => ({
|
|
58
|
+
components: { ButtonWithIcon },
|
|
59
|
+
setup() { return { args }; },
|
|
60
|
+
template: '<ButtonWithIcon v-bind="args">Button label</ButtonWithIcon>',
|
|
61
|
+
}),
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const Tertiary: Story = {
|
|
65
|
+
args: { variant: 'tertiary', size: 'md', icon: 'star', iconPosition: 'left' },
|
|
66
|
+
render: (args: ButtonWithIconProps) => ({
|
|
67
|
+
components: { ButtonWithIcon },
|
|
68
|
+
setup() { return { args }; },
|
|
69
|
+
template: '<ButtonWithIcon v-bind="args">Button label</ButtonWithIcon>',
|
|
70
|
+
}),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const IconRight: Story = {
|
|
74
|
+
args: { variant: 'primary', size: 'md', icon: 'books', iconPosition: 'right' },
|
|
75
|
+
render: (args: ButtonWithIconProps) => ({
|
|
76
|
+
components: { ButtonWithIcon },
|
|
77
|
+
setup() { return { args }; },
|
|
78
|
+
template: '<ButtonWithIcon v-bind="args">Browse books</ButtonWithIcon>',
|
|
79
|
+
}),
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const Small: Story = {
|
|
83
|
+
args: { variant: 'primary', size: 'sm', icon: 'star', iconSize: 'md', iconPosition: 'left' },
|
|
84
|
+
render: (args: ButtonWithIconProps) => ({
|
|
85
|
+
components: { ButtonWithIcon },
|
|
86
|
+
setup() { return { args }; },
|
|
87
|
+
template: '<ButtonWithIcon v-bind="args">Small button</ButtonWithIcon>',
|
|
88
|
+
}),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const Loading: Story = {
|
|
92
|
+
args: { variant: 'primary', size: 'md', icon: 'star', loading: true },
|
|
93
|
+
render: (args: ButtonWithIconProps) => ({
|
|
94
|
+
components: { ButtonWithIcon },
|
|
95
|
+
setup() { return { args }; },
|
|
96
|
+
template: '<ButtonWithIcon v-bind="args">Loading</ButtonWithIcon>',
|
|
97
|
+
}),
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const Disabled: Story = {
|
|
101
|
+
args: { variant: 'primary', size: 'md', icon: 'star', disabled: true },
|
|
102
|
+
render: (args: ButtonWithIconProps) => ({
|
|
103
|
+
components: { ButtonWithIcon },
|
|
104
|
+
setup() { return { args }; },
|
|
105
|
+
template: '<ButtonWithIcon v-bind="args">Disabled</ButtonWithIcon>',
|
|
106
|
+
}),
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const AsLink: Story = {
|
|
110
|
+
args: {
|
|
111
|
+
variant: 'primary',
|
|
112
|
+
size: 'md',
|
|
113
|
+
icon: 'books',
|
|
114
|
+
iconPosition: 'right',
|
|
115
|
+
href: 'https://example.com',
|
|
116
|
+
target: '_blank',
|
|
117
|
+
rel: 'noopener noreferrer',
|
|
118
|
+
} satisfies ButtonWithIconProps,
|
|
119
|
+
render: (args: ButtonWithIconProps) => ({
|
|
120
|
+
components: { ButtonWithIcon },
|
|
121
|
+
setup() { return { args }; },
|
|
122
|
+
template: '<ButtonWithIcon v-bind="args">Open link</ButtonWithIcon>',
|
|
123
|
+
}),
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const IconOnly: Story = {
|
|
127
|
+
render: () => ({
|
|
128
|
+
components: { ButtonWithIcon },
|
|
129
|
+
template: `
|
|
130
|
+
<div class="flex items-center gap-4">
|
|
131
|
+
<ButtonWithIcon icon="star" size="md" aria-label="Add to favourites" />
|
|
132
|
+
<ButtonWithIcon icon="star" size="sm" icon-size="md" aria-label="Add to favourites" />
|
|
133
|
+
</div>
|
|
134
|
+
`,
|
|
135
|
+
}),
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export const Variants: Story = {
|
|
139
|
+
render: () => ({
|
|
140
|
+
components: { ButtonWithIcon },
|
|
141
|
+
template: `
|
|
142
|
+
<div class="flex items-center gap-4">
|
|
143
|
+
<ButtonWithIcon icon="star" variant="primary">Primary</ButtonWithIcon>
|
|
144
|
+
<ButtonWithIcon icon="books" variant="secondary">Secondary</ButtonWithIcon>
|
|
145
|
+
<ButtonWithIcon icon="star" variant="tertiary">Tertiary</ButtonWithIcon>
|
|
146
|
+
</div>
|
|
147
|
+
`,
|
|
148
|
+
}),
|
|
149
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, useSlots } from 'vue';
|
|
3
|
+
import type { SimpleButtonProps } from '../SimpleButton/SimpleButton.vue';
|
|
4
|
+
import type { IconSize } from '../../types/icon';
|
|
5
|
+
import BaseIcon from '../BaseIcon/BaseIcon.vue';
|
|
6
|
+
import SimpleButton from '../SimpleButton/SimpleButton.vue';
|
|
7
|
+
|
|
8
|
+
export type ButtonWithIconProps = SimpleButtonProps & {
|
|
9
|
+
icon: string;
|
|
10
|
+
iconPath?: string;
|
|
11
|
+
iconSize?: IconSize;
|
|
12
|
+
iconPosition?: 'left' | 'right';
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const props = withDefaults(defineProps<ButtonWithIconProps>(), {
|
|
16
|
+
variant: 'primary',
|
|
17
|
+
size: 'md',
|
|
18
|
+
loading: false,
|
|
19
|
+
full: false,
|
|
20
|
+
disabled: false,
|
|
21
|
+
iconPath: '/icons',
|
|
22
|
+
iconSize: 'lg',
|
|
23
|
+
iconPosition: 'left',
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const slots = useSlots();
|
|
27
|
+
|
|
28
|
+
const isIconOnly = computed(() => {
|
|
29
|
+
const nodes = slots.default?.();
|
|
30
|
+
|
|
31
|
+
if (!nodes || nodes.length === 0) return true;
|
|
32
|
+
return false;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const buttonProps = computed(
|
|
36
|
+
(): SimpleButtonProps => ({
|
|
37
|
+
variant: props.variant,
|
|
38
|
+
size: props.size,
|
|
39
|
+
loading: props.loading,
|
|
40
|
+
full: props.full,
|
|
41
|
+
disabled: props.disabled,
|
|
42
|
+
href: props.href,
|
|
43
|
+
type: props.type,
|
|
44
|
+
name: props.name,
|
|
45
|
+
value: props.value,
|
|
46
|
+
target: props.target,
|
|
47
|
+
rel: props.rel,
|
|
48
|
+
download: props.download,
|
|
49
|
+
ariaLabel: props.ariaLabel,
|
|
50
|
+
})
|
|
51
|
+
);
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<template>
|
|
55
|
+
<SimpleButton
|
|
56
|
+
v-bind="buttonProps"
|
|
57
|
+
:class="{
|
|
58
|
+
'flex-row-reverse': props.iconPosition === 'right',
|
|
59
|
+
'buttonWithIcon--icon-only': isIconOnly,
|
|
60
|
+
}"
|
|
61
|
+
>
|
|
62
|
+
<BaseIcon
|
|
63
|
+
:name="props.icon"
|
|
64
|
+
:icon-path="props.iconPath"
|
|
65
|
+
:size="props.iconSize"
|
|
66
|
+
/>
|
|
67
|
+
<slot />
|
|
68
|
+
</SimpleButton>
|
|
69
|
+
</template>
|
|
70
|
+
|
|
71
|
+
<style scoped>
|
|
72
|
+
@reference "tailwindcss";
|
|
73
|
+
|
|
74
|
+
.buttonWithIcon--icon-only {
|
|
75
|
+
@apply p-0 aspect-square;
|
|
76
|
+
}
|
|
77
|
+
</style>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { ref } from 'vue';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
3
|
+
import type { ConcreteComponent } from 'vue';
|
|
4
|
+
import type { CheckboxInputProps } from './CheckboxInput.vue';
|
|
5
|
+
import CheckboxInput from './CheckboxInput.vue';
|
|
6
|
+
|
|
7
|
+
const meta: Meta<CheckboxInputProps> = {
|
|
8
|
+
title: 'Form/CheckboxInput',
|
|
9
|
+
component: CheckboxInput as unknown as ConcreteComponent<CheckboxInputProps>,
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
argTypes: {
|
|
12
|
+
size: { control: 'select', options: ['sm', 'md', 'lg'] },
|
|
13
|
+
invalid: { control: 'boolean' },
|
|
14
|
+
required: { control: 'boolean' },
|
|
15
|
+
disabled: { control: 'boolean' },
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default meta;
|
|
20
|
+
type Story = StoryObj<CheckboxInputProps>;
|
|
21
|
+
|
|
22
|
+
export const Default: Story = {
|
|
23
|
+
args: { name: 'accept', size: 'md' },
|
|
24
|
+
render: (args: CheckboxInputProps) => ({
|
|
25
|
+
components: { CheckboxInput },
|
|
26
|
+
setup() {
|
|
27
|
+
const model = ref(false);
|
|
28
|
+
return { args, model };
|
|
29
|
+
},
|
|
30
|
+
template: '<CheckboxInput v-bind="args" v-model="model">Zaakceptuj regulamin</CheckboxInput>',
|
|
31
|
+
}),
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const Checked: Story = {
|
|
35
|
+
args: { name: 'accept-checked', size: 'md' },
|
|
36
|
+
render: (args: CheckboxInputProps) => ({
|
|
37
|
+
components: { CheckboxInput },
|
|
38
|
+
setup() {
|
|
39
|
+
const model = ref(true);
|
|
40
|
+
return { args, model };
|
|
41
|
+
},
|
|
42
|
+
template: '<CheckboxInput v-bind="args" v-model="model">Zaakceptuj regulamin</CheckboxInput>',
|
|
43
|
+
}),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const Invalid: Story = {
|
|
47
|
+
args: { name: 'accept-invalid', size: 'md', invalid: true },
|
|
48
|
+
render: (args: CheckboxInputProps) => ({
|
|
49
|
+
components: { CheckboxInput },
|
|
50
|
+
setup() {
|
|
51
|
+
const model = ref(false);
|
|
52
|
+
return { args, model };
|
|
53
|
+
},
|
|
54
|
+
template: '<CheckboxInput v-bind="args" v-model="model">Pole wymagane</CheckboxInput>',
|
|
55
|
+
}),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const Disabled: Story = {
|
|
59
|
+
args: { name: 'accept-disabled', size: 'md', disabled: true },
|
|
60
|
+
render: (args: CheckboxInputProps) => ({
|
|
61
|
+
components: { CheckboxInput },
|
|
62
|
+
setup() {
|
|
63
|
+
const model = ref(false);
|
|
64
|
+
return { args, model };
|
|
65
|
+
},
|
|
66
|
+
template: '<CheckboxInput v-bind="args" v-model="model">Niedostępne</CheckboxInput>',
|
|
67
|
+
}),
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const DisabledChecked: Story = {
|
|
71
|
+
args: { name: 'accept-disabled-checked', size: 'md', disabled: true },
|
|
72
|
+
render: (args: CheckboxInputProps) => ({
|
|
73
|
+
components: { CheckboxInput },
|
|
74
|
+
setup() {
|
|
75
|
+
const model = ref(true);
|
|
76
|
+
return { args, model };
|
|
77
|
+
},
|
|
78
|
+
template: '<CheckboxInput v-bind="args" v-model="model">Niedostępne (zaznaczone)</CheckboxInput>',
|
|
79
|
+
}),
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const Sizes: Story = {
|
|
83
|
+
render: () => ({
|
|
84
|
+
components: { CheckboxInput },
|
|
85
|
+
setup() {
|
|
86
|
+
const sm = ref(false);
|
|
87
|
+
const md = ref(false);
|
|
88
|
+
const lg = ref(false);
|
|
89
|
+
return { sm, md, lg };
|
|
90
|
+
},
|
|
91
|
+
template: `
|
|
92
|
+
<div class="flex flex-col gap-4">
|
|
93
|
+
<CheckboxInput name="size-sm" size="sm" v-model="sm">Small (24px)</CheckboxInput>
|
|
94
|
+
<CheckboxInput name="size-md" size="md" v-model="md">Medium (28px)</CheckboxInput>
|
|
95
|
+
<CheckboxInput name="size-lg" size="lg" v-model="lg">Large (32px)</CheckboxInput>
|
|
96
|
+
</div>
|
|
97
|
+
`,
|
|
98
|
+
}),
|
|
99
|
+
};
|