@davidbirchall/core 1.0.8 → 1.0.9

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 (95) hide show
  1. package/dist/Button/types.d.ts +4 -0
  2. package/dist/Calendar/types.d.ts +22 -0
  3. package/{src/components/Card/types.ts → dist/Card/types.d.ts} +1 -1
  4. package/dist/Checkbox/types.d.ts +7 -0
  5. package/dist/DataTable/types.d.ts +11 -0
  6. package/dist/Dropdown/types.d.ts +13 -0
  7. package/dist/EmptyState/types.d.ts +8 -0
  8. package/dist/ErrorSummary/types.d.ts +4 -0
  9. package/dist/Heading/types.d.ts +6 -0
  10. package/dist/Input/types.d.ts +11 -0
  11. package/dist/Select/types.d.ts +15 -0
  12. package/dist/StatCard/types.d.ts +12 -0
  13. package/dist/Tag/types.d.ts +4 -0
  14. package/dist/TextArea/types.d.ts +11 -0
  15. package/dist/core.css +1 -0
  16. package/dist/core.js +24 -0
  17. package/dist/core.js.map +1 -0
  18. package/dist/core.umd.cjs +2 -0
  19. package/dist/core.umd.cjs.map +1 -0
  20. package/dist/index.d.ts +2 -0
  21. package/dist/package.json +27 -0
  22. package/package.json +4 -1
  23. package/.storybook/main.ts +0 -18
  24. package/.storybook/preview.ts +0 -14
  25. package/src/components/Badge/Badge.stories.ts +0 -147
  26. package/src/components/Badge/Badge.test.ts +0 -57
  27. package/src/components/Badge/Badge.vue +0 -79
  28. package/src/components/Button/Button.stories.ts +0 -80
  29. package/src/components/Button/Button.test.ts +0 -145
  30. package/src/components/Button/Button.vue +0 -108
  31. package/src/components/Button/types.ts +0 -4
  32. package/src/components/Calendar/Calendar.stories.ts +0 -261
  33. package/src/components/Calendar/Calendar.test.ts +0 -119
  34. package/src/components/Calendar/Calendar.vue +0 -528
  35. package/src/components/Calendar/types.ts +0 -20
  36. package/src/components/Card/Card.stories.ts +0 -88
  37. package/src/components/Card/Card.test.ts +0 -173
  38. package/src/components/Card/Card.vue +0 -59
  39. package/src/components/Checkbox/Checkbox.stories.ts +0 -126
  40. package/src/components/Checkbox/Checkbox.test.ts +0 -155
  41. package/src/components/Checkbox/Checkbox.vue +0 -121
  42. package/src/components/Checkbox/types.ts +0 -7
  43. package/src/components/DataTable/DataTable.stories.ts +0 -156
  44. package/src/components/DataTable/DataTable.test.ts +0 -185
  45. package/src/components/DataTable/DataTable.vue +0 -177
  46. package/src/components/DataTable/types.ts +0 -12
  47. package/src/components/DatePicker/DatePicker.stories.ts +0 -172
  48. package/src/components/DatePicker/DatePicker.test.ts +0 -87
  49. package/src/components/DatePicker/DatePicker.vue +0 -302
  50. package/src/components/Dropdown/Dropdown.stories.ts +0 -231
  51. package/src/components/Dropdown/Dropdown.vue +0 -314
  52. package/src/components/Dropdown/types.ts +0 -14
  53. package/src/components/EmptyState/EmptyState.stories.ts +0 -189
  54. package/src/components/EmptyState/EmptyState.vue +0 -215
  55. package/src/components/EmptyState/types.ts +0 -8
  56. package/src/components/ErrorSummary/ErrorSummary.vue +0 -78
  57. package/src/components/ErrorSummary/types.ts +0 -4
  58. package/src/components/FormGroup/FormGroup.stories.ts +0 -264
  59. package/src/components/FormGroup/FormGroup.test.ts +0 -63
  60. package/src/components/FormGroup/FormGroup.vue +0 -58
  61. package/src/components/Heading/Heading.stories.ts +0 -121
  62. package/src/components/Heading/Heading.test.ts +0 -184
  63. package/src/components/Heading/Heading.vue +0 -95
  64. package/src/components/Heading/types.ts +0 -6
  65. package/src/components/Input/Input.stories.ts +0 -172
  66. package/src/components/Input/Input.test.ts +0 -213
  67. package/src/components/Input/Input.vue +0 -121
  68. package/src/components/Input/types.ts +0 -11
  69. package/src/components/Modal/Modal.stories.ts +0 -341
  70. package/src/components/Modal/Modal.test.ts +0 -99
  71. package/src/components/Modal/Modal.vue +0 -278
  72. package/src/components/ProgressBar/ProgressBar.stories.ts +0 -313
  73. package/src/components/ProgressBar/ProgressBar.test.ts +0 -98
  74. package/src/components/ProgressBar/ProgressBar.vue +0 -117
  75. package/src/components/Select/Select.stories.ts +0 -177
  76. package/src/components/Select/Select.test.ts +0 -225
  77. package/src/components/Select/Select.vue +0 -147
  78. package/src/components/Select/types.ts +0 -16
  79. package/src/components/StatCard/StatCard.stories.ts +0 -274
  80. package/src/components/StatCard/StatCard.vue +0 -226
  81. package/src/components/StatCard/types.ts +0 -12
  82. package/src/components/Tag/Tag.stories.ts +0 -78
  83. package/src/components/Tag/Tag.test.ts +0 -50
  84. package/src/components/Tag/Tag.vue +0 -71
  85. package/src/components/Tag/types.ts +0 -4
  86. package/src/components/TextArea/TextArea.stories.ts +0 -171
  87. package/src/components/TextArea/TextArea.test.ts +0 -202
  88. package/src/components/TextArea/TextArea.vue +0 -122
  89. package/src/components/TextArea/types.ts +0 -11
  90. package/src/components/index.ts +0 -5
  91. package/src/test/setup.ts +0 -1
  92. package/src/vite-env.d.ts +0 -6
  93. package/tsconfig.json +0 -29
  94. package/vite.config.ts +0 -33
  95. package/vitest.config.ts +0 -28
@@ -1,78 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3'
2
- import Tag from './Tag.vue'
3
-
4
- const meta = {
5
- title: 'Components/Tag',
6
- component: Tag,
7
- tags: ['autodocs'],
8
- argTypes: {
9
- variant: {
10
- control: 'select',
11
- options: ['default', 'primary', 'success', 'warning', 'danger', 'info']
12
- },
13
- size: {
14
- control: 'select',
15
- options: ['small', 'medium', 'large']
16
- }
17
- },
18
- args: {
19
- variant: 'default',
20
- size: 'medium'
21
- }
22
- } satisfies Meta<typeof Tag>
23
-
24
- export default meta
25
- type Story = StoryObj<typeof meta>
26
-
27
- export const Default: Story = {
28
- render: (args: any) => ({
29
- components: { Tag },
30
- setup() {
31
- return { args }
32
- },
33
- template: '<Tag v-bind="args">Default Tag</Tag>'
34
- })
35
- }
36
-
37
- export const Variants: Story = {
38
- render: () => ({
39
- components: { Tag },
40
- template: `
41
- <div style="display: flex; gap: 1rem; flex-wrap: wrap;">
42
- <Tag variant="default">Default</Tag>
43
- <Tag variant="primary">Primary</Tag>
44
- <Tag variant="success">Success</Tag>
45
- <Tag variant="warning">Warning</Tag>
46
- <Tag variant="danger">Danger</Tag>
47
- <Tag variant="info">Info</Tag>
48
- </div>
49
- `
50
- })
51
- }
52
-
53
- export const Sizes: Story = {
54
- render: () => ({
55
- components: { Tag },
56
- template: `
57
- <div style="display: flex; gap: 1rem; align-items: center;">
58
- <Tag size="small" variant="primary">Small</Tag>
59
- <Tag size="medium" variant="primary">Medium</Tag>
60
- <Tag size="large" variant="primary">Large</Tag>
61
- </div>
62
- `
63
- })
64
- }
65
-
66
- export const SkillTags: Story = {
67
- render: () => ({
68
- components: { Tag },
69
- template: `
70
- <div style="display: flex; gap: 0.5rem; flex-wrap: wrap;">
71
- <Tag variant="primary" size="small">Unity</Tag>
72
- <Tag variant="success" size="small">C#</Tag>
73
- <Tag variant="info" size="small">Game Design</Tag>
74
- <Tag variant="warning" size="small">Blender</Tag>
75
- </div>
76
- `
77
- })
78
- }
@@ -1,50 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { mount } from '@vue/test-utils'
3
- import Tag from './Tag.vue'
4
-
5
- describe('Tag', () => {
6
- it('renders slot content', () => {
7
- const wrapper = mount(Tag, {
8
- slots: {
9
- default: 'Test Tag'
10
- }
11
- })
12
- expect(wrapper.text()).toBe('Test Tag')
13
- })
14
-
15
- it('applies default variant class', () => {
16
- const wrapper = mount(Tag)
17
- expect(wrapper.classes()).toContain('tag--default')
18
- })
19
-
20
- it('applies custom variant class', () => {
21
- const wrapper = mount(Tag, {
22
- props: { variant: 'primary' }
23
- })
24
- expect(wrapper.classes()).toContain('tag--primary')
25
- })
26
-
27
- it('applies default size class', () => {
28
- const wrapper = mount(Tag)
29
- expect(wrapper.classes()).toContain('tag--medium')
30
- })
31
-
32
- it('applies custom size class', () => {
33
- const wrapper = mount(Tag, {
34
- props: { size: 'small' }
35
- })
36
- expect(wrapper.classes()).toContain('tag--small')
37
- })
38
-
39
- it('applies multiple classes correctly', () => {
40
- const wrapper = mount(Tag, {
41
- props: {
42
- variant: 'success',
43
- size: 'large'
44
- }
45
- })
46
- expect(wrapper.classes()).toContain('tag')
47
- expect(wrapper.classes()).toContain('tag--success')
48
- expect(wrapper.classes()).toContain('tag--large')
49
- })
50
- })
@@ -1,71 +0,0 @@
1
- <template>
2
- <span :class="['tag', `tag--${variant}`, `tag--${size}`]">
3
- <slot />
4
- </span>
5
- </template>
6
-
7
- <script setup lang="ts">
8
- import type { TagProps } from './types'
9
-
10
- withDefaults(defineProps<TagProps>(), {
11
- variant: 'default',
12
- size: 'medium'
13
- })
14
- </script>
15
-
16
- <style scoped>
17
- .tag {
18
- display: inline-flex;
19
- align-items: center;
20
- font-weight: 600;
21
- border-radius: 0.375rem;
22
- transition: all 0.2s ease-in-out;
23
- }
24
-
25
- /* Sizes */
26
- .tag--small {
27
- padding: 0.25rem 0.5rem;
28
- font-size: 0.75rem;
29
- }
30
-
31
- .tag--medium {
32
- padding: 0.375rem 0.75rem;
33
- font-size: 0.875rem;
34
- }
35
-
36
- .tag--large {
37
- padding: 0.5rem 1rem;
38
- font-size: 1rem;
39
- }
40
-
41
- /* Variants */
42
- .tag--default {
43
- background-color: #f3f4f6;
44
- color: #374151;
45
- }
46
-
47
- .tag--primary {
48
- background-color: #dbeafe;
49
- color: #1e40af;
50
- }
51
-
52
- .tag--success {
53
- background-color: #d1fae5;
54
- color: #065f46;
55
- }
56
-
57
- .tag--warning {
58
- background-color: #fef3c7;
59
- color: #92400e;
60
- }
61
-
62
- .tag--danger {
63
- background-color: #fee2e2;
64
- color: #991b1b;
65
- }
66
-
67
- .tag--info {
68
- background-color: #e0e7ff;
69
- color: #3730a3;
70
- }
71
- </style>
@@ -1,4 +0,0 @@
1
- export interface TagProps {
2
- variant?: 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info'
3
- size?: 'small' | 'medium' | 'large'
4
- }
@@ -1,171 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3'
2
- import { ref } from 'vue'
3
- import TextArea from './TextArea.vue'
4
-
5
- const meta = {
6
- title: 'Form Fields/TextArea',
7
- component: TextArea,
8
- tags: ['autodocs'],
9
- argTypes: {
10
- label: {
11
- control: 'text',
12
- description: 'Label text'
13
- },
14
- placeholder: {
15
- control: 'text',
16
- description: 'Placeholder text'
17
- },
18
- rows: {
19
- control: 'number',
20
- description: 'Number of visible text lines'
21
- },
22
- disabled: {
23
- control: 'boolean',
24
- description: 'Disabled state'
25
- },
26
- required: {
27
- control: 'boolean',
28
- description: 'Required field'
29
- },
30
- error: {
31
- control: 'text',
32
- description: 'Error message'
33
- },
34
- hint: {
35
- control: 'text',
36
- description: 'Hint text'
37
- }
38
- },
39
- args: {
40
- rows: 4
41
- }
42
- } satisfies Meta<typeof TextArea>
43
-
44
- export default meta
45
- type Story = StoryObj<typeof meta>
46
-
47
- export const Default: Story = {
48
- args: {
49
- label: 'Message',
50
- placeholder: 'Enter your message'
51
- },
52
- render: (args: any) => ({
53
- components: { TextArea },
54
- setup() {
55
- const value = ref('')
56
- return { args, value }
57
- },
58
- template: '<TextArea v-bind="args" v-model="value" />'
59
- })
60
- }
61
-
62
- export const WithValue: Story = {
63
- args: {
64
- label: 'Description',
65
- modelValue: 'This is a sample description that spans multiple lines.\n\nIt can contain paragraphs and line breaks.'
66
- },
67
- render: (args: any) => ({
68
- components: { TextArea },
69
- setup() {
70
- const value = ref(args.modelValue ?? '')
71
- return { args, value }
72
- },
73
- template: '<TextArea v-bind="args" v-model="value" />'
74
- })
75
- }
76
-
77
- export const WithHint: Story = {
78
- args: {
79
- label: 'Comments',
80
- placeholder: 'Add your comments',
81
- hint: 'Maximum 500 characters'
82
- },
83
- render: (args: any) => ({
84
- components: { TextArea },
85
- setup() {
86
- const value = ref('')
87
- return { args, value }
88
- },
89
- template: '<TextArea v-bind="args" v-model="value" />'
90
- })
91
- }
92
-
93
- export const WithError: Story = {
94
- args: {
95
- label: 'Feedback',
96
- modelValue: 'Too short',
97
- error: 'Feedback must be at least 50 characters'
98
- },
99
- render: (args: any) => ({
100
- components: { TextArea },
101
- setup() {
102
- const value = ref(args.modelValue ?? '')
103
- return { args, value }
104
- },
105
- template: '<TextArea v-bind="args" v-model="value" />'
106
- })
107
- }
108
-
109
- export const Required: Story = {
110
- args: {
111
- label: 'Description',
112
- placeholder: 'Describe the issue',
113
- required: true
114
- },
115
- render: (args: any) => ({
116
- components: { TextArea },
117
- setup() {
118
- const value = ref('')
119
- return { args, value }
120
- },
121
- template: '<TextArea v-bind="args" v-model="value" />'
122
- })
123
- }
124
-
125
- export const Disabled: Story = {
126
- args: {
127
- label: 'Read Only',
128
- modelValue: 'This content cannot be edited',
129
- disabled: true
130
- },
131
- render: (args: any) => ({
132
- components: { TextArea },
133
- setup() {
134
- const value = ref(args.modelValue ?? '')
135
- return { args, value }
136
- },
137
- template: '<TextArea v-bind="args" v-model="value" />'
138
- })
139
- }
140
-
141
- export const CustomRows: Story = {
142
- args: {
143
- label: 'Short Note',
144
- placeholder: 'Brief note',
145
- rows: 2
146
- },
147
- render: (args: any) => ({
148
- components: { TextArea },
149
- setup() {
150
- const value = ref('')
151
- return { args, value }
152
- },
153
- template: '<TextArea v-bind="args" v-model="value" />'
154
- })
155
- }
156
-
157
- export const LargeTextArea: Story = {
158
- args: {
159
- label: 'Article Content',
160
- placeholder: 'Write your article content here',
161
- rows: 10
162
- },
163
- render: (args: any) => ({
164
- components: { TextArea },
165
- setup() {
166
- const value = ref('')
167
- return { args, value }
168
- },
169
- template: '<TextArea v-bind="args" v-model="value" />'
170
- })
171
- }
@@ -1,202 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { render, screen } from '@testing-library/vue'
3
- import userEvent from '@testing-library/user-event'
4
- import TextArea from './TextArea.vue'
5
-
6
- describe('TextArea', () => {
7
- describe('rendering', () => {
8
- it('renders with label', () => {
9
- render(TextArea, {
10
- props: {
11
- label: 'Message'
12
- }
13
- })
14
-
15
- expect(screen.getByText('Message')).toBeInTheDocument()
16
- })
17
-
18
- it('renders without label', () => {
19
- const { container } = render(TextArea)
20
-
21
- expect(container.querySelector('.textarea-label')).not.toBeInTheDocument()
22
- })
23
-
24
- it('renders placeholder', () => {
25
- render(TextArea, {
26
- props: {
27
- placeholder: 'Enter your message'
28
- }
29
- })
30
-
31
- expect(screen.getByPlaceholderText('Enter your message')).toBeInTheDocument()
32
- })
33
-
34
- it('renders error message', () => {
35
- render(TextArea, {
36
- props: {
37
- error: 'This field is required'
38
- }
39
- })
40
-
41
- expect(screen.getByText('This field is required')).toBeInTheDocument()
42
- })
43
-
44
- it('renders hint text', () => {
45
- render(TextArea, {
46
- props: {
47
- hint: 'Maximum 500 characters'
48
- }
49
- })
50
-
51
- expect(screen.getByText('Maximum 500 characters')).toBeInTheDocument()
52
- })
53
-
54
- it('does not show hint when error is present', () => {
55
- render(TextArea, {
56
- props: {
57
- hint: 'Helper text',
58
- error: 'Error message'
59
- }
60
- })
61
-
62
- expect(screen.queryByText('Helper text')).not.toBeInTheDocument()
63
- expect(screen.getByText('Error message')).toBeInTheDocument()
64
- })
65
-
66
- it('shows required asterisk when required', () => {
67
- render(TextArea, {
68
- props: {
69
- label: 'Comments',
70
- required: true
71
- }
72
- })
73
-
74
- expect(screen.getByText('*')).toBeInTheDocument()
75
- })
76
-
77
- it('applies error class when error prop is set', () => {
78
- render(TextArea, {
79
- props: {
80
- error: 'Error'
81
- }
82
- })
83
-
84
- const textarea = screen.getByRole('textbox')
85
- expect(textarea).toHaveClass('textarea-field--error')
86
- })
87
-
88
- it('sets custom rows attribute', () => {
89
- render(TextArea, {
90
- props: {
91
- rows: 8
92
- }
93
- })
94
-
95
- const textarea = screen.getByRole('textbox')
96
- expect(textarea).toHaveAttribute('rows', '8')
97
- })
98
-
99
- it('uses default rows value of 4', () => {
100
- render(TextArea)
101
-
102
- const textarea = screen.getByRole('textbox')
103
- expect(textarea).toHaveAttribute('rows', '4')
104
- })
105
- })
106
-
107
- describe('v-model', () => {
108
- it('displays initial value', () => {
109
- render(TextArea, {
110
- props: {
111
- modelValue: 'Initial text'
112
- }
113
- })
114
-
115
- const textarea = screen.getByRole('textbox') as HTMLTextAreaElement
116
- expect(textarea.value).toBe('Initial text')
117
- })
118
-
119
- it('emits update:modelValue on input', async () => {
120
- const user = userEvent.setup()
121
- const { emitted } = render(TextArea)
122
-
123
- const textarea = screen.getByRole('textbox')
124
- await user.type(textarea, 'test')
125
-
126
- expect(emitted()['update:modelValue']).toBeTruthy()
127
- expect(emitted()['update:modelValue'].length).toBeGreaterThan(0)
128
- })
129
-
130
- it('handles multiline input', async () => {
131
- const user = userEvent.setup()
132
- const { emitted } = render(TextArea)
133
-
134
- const textarea = screen.getByRole('textbox')
135
- await user.type(textarea, 'Line 1{Enter}Line 2')
136
-
137
- const emissions = emitted()['update:modelValue'] as any[]
138
- expect(emissions).toBeTruthy()
139
- const lastEmission = emissions[emissions.length - 1][0] as string
140
- expect(lastEmission).toContain('\n')
141
- })
142
- })
143
-
144
- describe('disabled state', () => {
145
- it('disables the textarea when disabled prop is true', () => {
146
- render(TextArea, {
147
- props: {
148
- disabled: true
149
- }
150
- })
151
-
152
- const textarea = screen.getByRole('textbox')
153
- expect(textarea).toBeDisabled()
154
- })
155
-
156
- it('applies disabled class', () => {
157
- render(TextArea, {
158
- props: {
159
- disabled: true
160
- }
161
- })
162
-
163
- const textarea = screen.getByRole('textbox')
164
- expect(textarea).toHaveClass('textarea-field--disabled')
165
- })
166
- })
167
-
168
- describe('required attribute', () => {
169
- it('sets required attribute when required prop is true', () => {
170
- render(TextArea, {
171
- props: {
172
- required: true
173
- }
174
- })
175
-
176
- const textarea = screen.getByRole('textbox')
177
- expect(textarea).toBeRequired()
178
- })
179
-
180
- it('does not set required attribute by default', () => {
181
- render(TextArea)
182
-
183
- const textarea = screen.getByRole('textbox')
184
- expect(textarea).not.toBeRequired()
185
- })
186
- })
187
-
188
- describe('accessibility', () => {
189
- it('associates label with textarea using htmlFor', () => {
190
- render(TextArea, {
191
- props: {
192
- label: 'Message'
193
- }
194
- })
195
-
196
- const label = screen.getByText('Message') as HTMLLabelElement
197
- const textarea = screen.getByRole('textbox')
198
-
199
- expect(label.htmlFor).toBe(textarea.id)
200
- })
201
- })
202
- })
@@ -1,122 +0,0 @@
1
- <template>
2
- <div class="textarea-wrapper">
3
- <label v-if="label" :for="textareaId" class="textarea-label">
4
- {{ label }}
5
- </label>
6
- <textarea
7
- :id="textareaId"
8
- :value="modelValue"
9
- :placeholder="placeholder"
10
- :disabled="disabled"
11
- :required="required"
12
- :rows="rows"
13
- :class="['textarea-field', { 'textarea-field--error': error, 'textarea-field--disabled': disabled }]"
14
- @input="handleInput"
15
- />
16
- <span v-if="error" class="textarea-error">{{ error }}</span>
17
- <span v-if="hint && !error" class="textarea-hint">{{ hint }}</span>
18
- </div>
19
- </template>
20
-
21
- <script setup lang="ts">
22
- import { computed } from 'vue'
23
-
24
- let componentIdCounter = 0
25
-
26
- export interface TextAreaProps {
27
- modelValue?: string
28
- id?: string
29
- label?: string
30
- placeholder?: string
31
- disabled?: boolean
32
- required?: boolean
33
- rows?: number
34
- error?: string
35
- hint?: string
36
- }
37
-
38
- const props = withDefaults(defineProps<TextAreaProps>(), {
39
- rows: 4,
40
- disabled: false,
41
- required: false
42
- })
43
-
44
- const emit = defineEmits<{
45
- 'update:modelValue': [value: string]
46
- }>()
47
-
48
- const generatedId = `textarea-${++componentIdCounter}`
49
- const textareaId = computed(() => props.id || generatedId)
50
-
51
- const handleInput = (event: Event) => {
52
- const target = event.target as HTMLTextAreaElement
53
- emit('update:modelValue', target.value)
54
- }
55
- </script>
56
-
57
- <style scoped>
58
- .textarea-wrapper {
59
- display: flex;
60
- flex-direction: column;
61
- gap: 0.375rem;
62
- }
63
-
64
- .textarea-label {
65
- font-size: 0.875rem;
66
- font-weight: 500;
67
- color: #374151;
68
- }
69
-
70
-
71
- .textarea-field {
72
- padding: 0.625rem 0.875rem;
73
- font-size: 1rem;
74
- font-family: inherit;
75
- border: 1px solid #d1d5db;
76
- border-radius: 0.375rem;
77
- outline: none;
78
- transition: all 0.2s ease-in-out;
79
- background: white;
80
- color: #1f2937;
81
- resize: vertical;
82
- min-height: 2.5rem;
83
- }
84
-
85
- .textarea-field::placeholder {
86
- color: #9ca3af;
87
- }
88
-
89
- .textarea-field:focus {
90
- border-color: #3b82f6;
91
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
92
- }
93
-
94
- .textarea-field--error {
95
- border-color: #fca5a5;
96
- border-bottom: 2px solid #dc2626;
97
- background: #fef2f2;
98
- }
99
-
100
- .textarea-field--error:focus {
101
- border-color: #fca5a5;
102
- border-bottom: 2px solid #dc2626;
103
- box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.12);
104
- }
105
-
106
- .textarea-field--disabled {
107
- background: #f3f4f6;
108
- cursor: not-allowed;
109
- opacity: 0.6;
110
- resize: none;
111
- }
112
-
113
- .textarea-error {
114
- font-size: 0.75rem;
115
- color: #ef4444;
116
- }
117
-
118
- .textarea-hint {
119
- font-size: 0.75rem;
120
- color: #6b7280;
121
- }
122
- </style>
@@ -1,11 +0,0 @@
1
- export interface TextAreaProps {
2
- modelValue?: string
3
- id?: string
4
- label?: string
5
- placeholder?: string
6
- disabled?: boolean
7
- required?: boolean
8
- rows?: number
9
- error?: string
10
- hint?: string
11
- }