@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,213 +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 Input from './Input.vue'
5
-
6
- describe('Input', () => {
7
- describe('rendering', () => {
8
- it('renders with label', () => {
9
- render(Input, {
10
- props: {
11
- label: 'Email'
12
- }
13
- })
14
-
15
- expect(screen.getByText('Email')).toBeInTheDocument()
16
- })
17
-
18
- it('renders without label', () => {
19
- const { container } = render(Input)
20
-
21
- expect(container.querySelector('.input-label')).not.toBeInTheDocument()
22
- })
23
-
24
- it('renders placeholder', () => {
25
- render(Input, {
26
- props: {
27
- placeholder: 'Enter text'
28
- }
29
- })
30
-
31
- expect(screen.getByPlaceholderText('Enter text')).toBeInTheDocument()
32
- })
33
-
34
- it('renders error message', () => {
35
- render(Input, {
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(Input, {
46
- props: {
47
- hint: 'Must be at least 8 characters'
48
- }
49
- })
50
-
51
- expect(screen.getByText('Must be at least 8 characters')).toBeInTheDocument()
52
- })
53
-
54
- it('does not show hint when error is present', () => {
55
- render(Input, {
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(Input, {
68
- props: {
69
- label: 'Name',
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(Input, {
79
- props: {
80
- error: 'Error'
81
- }
82
- })
83
-
84
- const input = screen.getByRole('textbox')
85
- expect(input).toHaveClass('input-field--error')
86
- })
87
- })
88
-
89
- describe('input types', () => {
90
- it('renders as text input by default', () => {
91
- render(Input)
92
-
93
- const input = screen.getByRole('textbox')
94
- expect(input).toHaveAttribute('type', 'text')
95
- })
96
-
97
- it('renders as email input', () => {
98
- render(Input, {
99
- props: {
100
- type: 'email'
101
- }
102
- })
103
-
104
- const input = screen.getByRole('textbox')
105
- expect(input).toHaveAttribute('type', 'email')
106
- })
107
-
108
- it('renders as password input', () => {
109
- render(Input, {
110
- props: {
111
- type: 'password'
112
- }
113
- })
114
-
115
- const input = document.querySelector('input[type="password"]')
116
- expect(input).toBeInTheDocument()
117
- })
118
-
119
- it('renders as number input', () => {
120
- render(Input, {
121
- props: {
122
- type: 'number'
123
- }
124
- })
125
-
126
- const input = screen.getByRole('spinbutton')
127
- expect(input).toHaveAttribute('type', 'number')
128
- })
129
- })
130
-
131
- describe('v-model', () => {
132
- it('displays initial value', () => {
133
- render(Input, {
134
- props: {
135
- modelValue: 'Initial value'
136
- }
137
- })
138
-
139
- const input = screen.getByRole('textbox') as HTMLInputElement
140
- expect(input.value).toBe('Initial value')
141
- })
142
-
143
- it('emits update:modelValue on input', async () => {
144
- const user = userEvent.setup()
145
- const { emitted } = render(Input)
146
-
147
- const input = screen.getByRole('textbox')
148
- await user.type(input, 'test')
149
-
150
- expect(emitted()['update:modelValue']).toBeTruthy()
151
- expect(emitted()['update:modelValue'].length).toBeGreaterThan(0)
152
- })
153
- })
154
-
155
- describe('disabled state', () => {
156
- it('disables the input when disabled prop is true', () => {
157
- render(Input, {
158
- props: {
159
- disabled: true
160
- }
161
- })
162
-
163
- const input = screen.getByRole('textbox')
164
- expect(input).toBeDisabled()
165
- })
166
-
167
- it('applies disabled class', () => {
168
- render(Input, {
169
- props: {
170
- disabled: true
171
- }
172
- })
173
-
174
- const input = screen.getByRole('textbox')
175
- expect(input).toHaveClass('input-field--disabled')
176
- })
177
- })
178
-
179
- describe('required attribute', () => {
180
- it('sets required attribute when required prop is true', () => {
181
- render(Input, {
182
- props: {
183
- required: true
184
- }
185
- })
186
-
187
- const input = screen.getByRole('textbox')
188
- expect(input).toBeRequired()
189
- })
190
-
191
- it('does not set required attribute by default', () => {
192
- render(Input)
193
-
194
- const input = screen.getByRole('textbox')
195
- expect(input).not.toBeRequired()
196
- })
197
- })
198
-
199
- describe('accessibility', () => {
200
- it('associates label with input using htmlFor', () => {
201
- render(Input, {
202
- props: {
203
- label: 'Username'
204
- }
205
- })
206
-
207
- const label = screen.getByText('Username') as HTMLLabelElement
208
- const input = screen.getByRole('textbox')
209
-
210
- expect(label.htmlFor).toBe(input.id)
211
- })
212
- })
213
- })
@@ -1,121 +0,0 @@
1
- <template>
2
- <div class="input-wrapper">
3
- <label v-if="label" :for="inputId" class="input-label">
4
- {{ label }}
5
- </label>
6
- <input
7
- :id="inputId"
8
- :type="type"
9
- :value="modelValue"
10
- :placeholder="placeholder"
11
- :disabled="disabled"
12
- :required="required"
13
- :class="['input-field', { 'input-field--error': error, 'input-field--disabled': disabled }]"
14
- @input="handleInput"
15
- />
16
- <span v-if="error" class="input-error">{{ error }}</span>
17
- <span v-if="hint && !error" class="input-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 InputProps {
27
- modelValue?: string | number
28
- id?: string
29
- label?: string
30
- type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'time'
31
- placeholder?: string
32
- disabled?: boolean
33
- required?: boolean
34
- error?: string
35
- hint?: string
36
- }
37
-
38
- const props = withDefaults(defineProps<InputProps>(), {
39
- type: 'text',
40
- disabled: false,
41
- required: false
42
- })
43
-
44
- const emit = defineEmits<{
45
- 'update:modelValue': [value: string]
46
- }>()
47
-
48
- const generatedId = `input-${++componentIdCounter}`
49
- const inputId = computed(() => props.id || generatedId)
50
-
51
- const handleInput = (event: Event) => {
52
- const target = event.target as HTMLInputElement
53
- emit('update:modelValue', target.value)
54
- }
55
- </script>
56
-
57
- <style scoped>
58
- .input-wrapper {
59
- display: flex;
60
- flex-direction: column;
61
- gap: 0.375rem;
62
- }
63
-
64
- .input-label {
65
- font-size: 0.875rem;
66
- font-weight: 500;
67
- color: #374151;
68
- }
69
-
70
-
71
- .input-field {
72
- padding: 0.75rem 0.875rem;
73
- font-size: 1rem;
74
- line-height: 1.5;
75
- height: 48px;
76
- border: 1px solid #d1d5db;
77
- border-radius: 0.375rem;
78
- outline: none;
79
- transition: all 0.2s ease-in-out;
80
- background: white;
81
- color: #1f2937;
82
- box-sizing: border-box;
83
- }
84
-
85
- .input-field::placeholder {
86
- color: #9ca3af;
87
- }
88
-
89
- .input-field:focus {
90
- border-color: #3b82f6;
91
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
92
- }
93
-
94
- .input-field--error {
95
- border-color: #fca5a5;
96
- border-bottom: 2px solid #dc2626;
97
- background: #fef2f2;
98
- }
99
-
100
- .input-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
- .input-field--disabled {
107
- background: #f3f4f6;
108
- cursor: not-allowed;
109
- opacity: 0.6;
110
- }
111
-
112
- .input-error {
113
- font-size: 0.75rem;
114
- color: #ef4444;
115
- }
116
-
117
- .input-hint {
118
- font-size: 0.75rem;
119
- color: #6b7280;
120
- }
121
- </style>
@@ -1,11 +0,0 @@
1
- export interface InputProps {
2
- modelValue?: string | number
3
- id?: string
4
- label?: string
5
- type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'time'
6
- placeholder?: string
7
- disabled?: boolean
8
- required?: boolean
9
- error?: string
10
- hint?: string
11
- }
@@ -1,341 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3'
2
- import { ref } from 'vue'
3
- import Modal from './Modal.vue'
4
-
5
- const meta = {
6
- title: 'Components/Modal',
7
- component: Modal,
8
- tags: ['autodocs'],
9
- argTypes: {
10
- modelValue: {
11
- control: 'boolean',
12
- description: 'Modal visibility state'
13
- },
14
- title: {
15
- control: 'text',
16
- description: 'Modal title'
17
- },
18
- size: {
19
- control: 'select',
20
- options: ['small', 'medium', 'large'],
21
- description: 'Modal size'
22
- },
23
- closable: {
24
- control: 'boolean',
25
- description: 'Show close button'
26
- },
27
- closeOnOverlay: {
28
- control: 'boolean',
29
- description: 'Close when clicking overlay'
30
- }
31
- },
32
- args: {
33
- title: 'Modal Title',
34
- size: 'medium',
35
- closable: true,
36
- closeOnOverlay: true
37
- }
38
- } satisfies Meta<typeof Modal>
39
-
40
- export default meta
41
- type Story = StoryObj<typeof meta>
42
-
43
- export const Default: Story = {
44
- render: (args: any) => ({
45
- components: { Modal },
46
- setup() {
47
- const isOpen = ref(false)
48
- return { isOpen, args }
49
- },
50
- template: `
51
- <div>
52
- <button
53
- @click="isOpen = true"
54
- style="padding: 0.625rem 1.25rem; background: #667eea; color: white; border: none; border-radius: 0.375rem; cursor: pointer; font-weight: 600;"
55
- >
56
- Open Modal
57
- </button>
58
- <Modal v-model="isOpen" v-bind="args">
59
- <p>This is the modal content. You can put any content here.</p>
60
- </Modal>
61
- </div>
62
- `
63
- })
64
- }
65
-
66
- export const WithFooter: Story = {
67
- render: (args: any) => ({
68
- components: { Modal },
69
- setup() {
70
- const isOpen = ref(false)
71
- return { isOpen, args }
72
- },
73
- template: `
74
- <div>
75
- <button
76
- @click="isOpen = true"
77
- style="padding: 0.625rem 1.25rem; background: #667eea; color: white; border: none; border-radius: 0.375rem; cursor: pointer; font-weight: 600;"
78
- >
79
- Open Modal
80
- </button>
81
- <Modal v-model="isOpen" title="Confirm Action" v-bind="args">
82
- <p>Are you sure you want to continue with this action?</p>
83
- <template #footer>
84
- <div style="display: flex; gap: 0.75rem; justify-content: flex-end;">
85
- <button
86
- @click="isOpen = false"
87
- style="padding: 0.5rem 1rem; background: #e5e7eb; color: #374151; border: none; border-radius: 0.375rem; cursor: pointer; font-weight: 500;"
88
- >
89
- Cancel
90
- </button>
91
- <button
92
- @click="isOpen = false"
93
- style="padding: 0.5rem 1rem; background: #667eea; color: white; border: none; border-radius: 0.375rem; cursor: pointer; font-weight: 500;"
94
- >
95
- Confirm
96
- </button>
97
- </div>
98
- </template>
99
- </Modal>
100
- </div>
101
- `
102
- })
103
- }
104
-
105
- export const Small: Story = {
106
- args: {
107
- size: 'small',
108
- title: 'Small Modal'
109
- },
110
- render: (args: any) => ({
111
- components: { Modal },
112
- setup() {
113
- const isOpen = ref(false)
114
- return { isOpen, args }
115
- },
116
- template: `
117
- <div>
118
- <button
119
- @click="isOpen = true"
120
- style="padding: 0.625rem 1.25rem; background: #667eea; color: white; border: none; border-radius: 0.375rem; cursor: pointer; font-weight: 600;"
121
- >
122
- Open Small Modal
123
- </button>
124
- <Modal v-model="isOpen" v-bind="args">
125
- <p>This is a small modal with limited content.</p>
126
- </Modal>
127
- </div>
128
- `
129
- })
130
- }
131
-
132
- export const Large: Story = {
133
- args: {
134
- size: 'large',
135
- title: 'Large Modal'
136
- },
137
- render: (args: any) => ({
138
- components: { Modal },
139
- setup() {
140
- const isOpen = ref(false)
141
- return { isOpen, args }
142
- },
143
- template: `
144
- <div>
145
- <button
146
- @click="isOpen = true"
147
- style="padding: 0.625rem 1.25rem; background: #667eea; color: white; border: none; border-radius: 0.375rem; cursor: pointer; font-weight: 600;"
148
- >
149
- Open Large Modal
150
- </button>
151
- <Modal v-model="isOpen" v-bind="args">
152
- <div style="min-height: 400px;">
153
- <h3>Large Content Area</h3>
154
- <p>This modal has more space for content.</p>
155
- <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
156
- <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
157
- </div>
158
- </Modal>
159
- </div>
160
- `
161
- })
162
- }
163
-
164
- export const NoClose: Story = {
165
- args: {
166
- closable: false,
167
- closeOnOverlay: false,
168
- title: 'Important Message'
169
- },
170
- render: (args: any) => ({
171
- components: { Modal },
172
- setup() {
173
- const isOpen = ref(false)
174
- return { isOpen, args }
175
- },
176
- template: `
177
- <div>
178
- <button
179
- @click="isOpen = true"
180
- style="padding: 0.625rem 1.25rem; background: #667eea; color: white; border: none; border-radius: 0.375rem; cursor: pointer; font-weight: 600;"
181
- >
182
- Open Modal (No Close)
183
- </button>
184
- <Modal v-model="isOpen" v-bind="args">
185
- <p>This modal cannot be closed by clicking outside or using the X button.</p>
186
- <template #footer>
187
- <button
188
- @click="isOpen = false"
189
- style="padding: 0.5rem 1rem; background: #667eea; color: white; border: none; border-radius: 0.375rem; cursor: pointer; font-weight: 500;"
190
- >
191
- I Understand
192
- </button>
193
- </template>
194
- </Modal>
195
- </div>
196
- `
197
- })
198
- }
199
-
200
- export const CustomHeader: Story = {
201
- render: (args: any) => ({
202
- components: { Modal },
203
- setup() {
204
- const isOpen = ref(false)
205
- return { isOpen, args }
206
- },
207
- template: `
208
- <div>
209
- <button
210
- @click="isOpen = true"
211
- style="padding: 0.625rem 1.25rem; background: #667eea; color: white; border: none; border-radius: 0.375rem; cursor: pointer; font-weight: 600;"
212
- >
213
- Open Modal
214
- </button>
215
- <Modal v-model="isOpen">
216
- <template #header>
217
- <div style="display: flex; align-items: center; gap: 0.75rem;">
218
- <span style="font-size: 1.5rem;">✨</span>
219
- <h3 style="margin: 0; font-size: 1.25rem; color: #667eea;">Custom Header</h3>
220
- </div>
221
- </template>
222
- <p>This modal has a custom header with an icon and styled text.</p>
223
- </Modal>
224
- </div>
225
- `
226
- })
227
- }
228
-
229
- export const FormModal: Story = {
230
- render: () => ({
231
- components: { Modal },
232
- setup() {
233
- const isOpen = ref(false)
234
- const formData = ref({ name: '', email: '' })
235
-
236
- const handleSubmit = () => {
237
- console.log('Form submitted:', formData.value)
238
- isOpen.value = false
239
- }
240
-
241
- return { isOpen, formData, handleSubmit }
242
- },
243
- template: `
244
- <div>
245
- <button
246
- @click="isOpen = true"
247
- style="padding: 0.625rem 1.25rem; background: #667eea; color: white; border: none; border-radius: 0.375rem; cursor: pointer; font-weight: 600;"
248
- >
249
- Add User
250
- </button>
251
- <Modal v-model="isOpen" title="Add New User">
252
- <form @submit.prevent="handleSubmit">
253
- <div style="margin-bottom: 1rem;">
254
- <label style="display: block; margin-bottom: 0.5rem; font-weight: 600;">Name</label>
255
- <input
256
- v-model="formData.name"
257
- type="text"
258
- placeholder="Enter name"
259
- required
260
- style="width: 100%; padding: 0.5rem; border: 1px solid #d1d5db; border-radius: 0.375rem;"
261
- />
262
- </div>
263
- <div style="margin-bottom: 1rem;">
264
- <label style="display: block; margin-bottom: 0.5rem; font-weight: 600;">Email</label>
265
- <input
266
- v-model="formData.email"
267
- type="email"
268
- placeholder="Enter email"
269
- required
270
- style="width: 100%; padding: 0.5rem; border: 1px solid #d1d5db; border-radius: 0.375rem;"
271
- />
272
- </div>
273
- </form>
274
- <template #footer>
275
- <div style="display: flex; gap: 0.75rem; justify-content: flex-end;">
276
- <button
277
- @click="isOpen = false"
278
- type="button"
279
- style="padding: 0.5rem 1rem; background: #e5e7eb; color: #374151; border: none; border-radius: 0.375rem; cursor: pointer; font-weight: 500;"
280
- >
281
- Cancel
282
- </button>
283
- <button
284
- @click="handleSubmit"
285
- type="submit"
286
- style="padding: 0.5rem 1rem; background: #667eea; color: white; border: none; border-radius: 0.375rem; cursor: pointer; font-weight: 500;"
287
- >
288
- Add User
289
- </button>
290
- </div>
291
- </template>
292
- </Modal>
293
- </div>
294
- `
295
- })
296
- }
297
-
298
- export const ConfirmDialog: Story = {
299
- render: () => ({
300
- components: { Modal },
301
- setup() {
302
- const isOpen = ref(false)
303
-
304
- const handleDelete = () => {
305
- console.log('Item deleted')
306
- isOpen.value = false
307
- }
308
-
309
- return { isOpen, handleDelete }
310
- },
311
- template: `
312
- <div>
313
- <button
314
- @click="isOpen = true"
315
- style="padding: 0.625rem 1.25rem; background: #dc2626; color: white; border: none; border-radius: 0.375rem; cursor: pointer; font-weight: 600;"
316
- >
317
- Delete Item
318
- </button>
319
- <Modal v-model="isOpen" title="Confirm Deletion" size="small">
320
- <p style="margin: 0;">Are you sure you want to delete this item? This action cannot be undone.</p>
321
- <template #footer>
322
- <div style="display: flex; gap: 0.75rem; justify-content: flex-end;">
323
- <button
324
- @click="isOpen = false"
325
- style="padding: 0.5rem 1rem; background: #e5e7eb; color: #374151; border: none; border-radius: 0.375rem; cursor: pointer; font-weight: 500;"
326
- >
327
- Cancel
328
- </button>
329
- <button
330
- @click="handleDelete"
331
- style="padding: 0.5rem 1rem; background: #dc2626; color: white; border: none; border-radius: 0.375rem; cursor: pointer; font-weight: 500;"
332
- >
333
- Delete
334
- </button>
335
- </div>
336
- </template>
337
- </Modal>
338
- </div>
339
- `
340
- })
341
- }