@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,314 +0,0 @@
1
- <template>
2
- <div
3
- ref="dropdownRef"
4
- class="dropdown"
5
- :class="{ 'dropdown--disabled': disabled }"
6
- >
7
- <div @click="toggleDropdown" class="dropdown__trigger">
8
- <slot name="trigger">
9
- <button type="button" class="dropdown__button">
10
- Menu
11
- </button>
12
- </slot>
13
- </div>
14
-
15
- <Teleport to="body">
16
- <Transition name="dropdown-fade">
17
- <div
18
- v-if="isOpen"
19
- ref="dropdownMenuRef"
20
- class="dropdown__menu"
21
- :class="`dropdown__menu--${placement}`"
22
- :style="menuStyles"
23
- @click="handleMenuClick"
24
- >
25
- <div v-if="$slots.header" class="dropdown__header">
26
- <slot name="header" />
27
- </div>
28
-
29
- <div class="dropdown__content">
30
- <slot>
31
- <template v-for="(item, index) in items" :key="index">
32
- <div v-if="item.divider" class="dropdown__divider" />
33
- <button
34
- v-else
35
- type="button"
36
- class="dropdown__item"
37
- :class="{ 'dropdown__item--disabled': item.disabled }"
38
- :disabled="item.disabled"
39
- @click="() => handleItemClick(item)"
40
- >
41
- <span v-if="item.icon" class="dropdown__item-icon">{{ item.icon }}</span>
42
- <span class="dropdown__item-label">{{ item.label }}</span>
43
- </button>
44
- </template>
45
- </slot>
46
- </div>
47
-
48
- <div v-if="$slots.footer" class="dropdown__footer">
49
- <slot name="footer" />
50
- </div>
51
- </div>
52
- </Transition>
53
- </Teleport>
54
- </div>
55
- </template>
56
-
57
- <script setup lang="ts">
58
- import { ref, computed, onMounted, onUnmounted } from 'vue'
59
- import type { DropdownProps, DropdownItem } from './types'
60
-
61
- const props = withDefaults(defineProps<DropdownProps>(), {
62
- items: () => [],
63
- placement: 'bottom-left',
64
- closeOnClick: true,
65
- disabled: false
66
- })
67
-
68
- const emit = defineEmits<{
69
- select: [item: DropdownItem]
70
- open: []
71
- close: []
72
- }>()
73
-
74
- const dropdownRef = ref<HTMLElement | null>(null)
75
- const dropdownMenuRef = ref<HTMLElement | null>(null)
76
- const isOpen = ref(false)
77
- const menuStyles = ref<Record<string, string>>({})
78
-
79
- const toggleDropdown = () => {
80
- if (props.disabled) return
81
-
82
- if (isOpen.value) {
83
- closeDropdown()
84
- } else {
85
- openDropdown()
86
- }
87
- }
88
-
89
- const openDropdown = () => {
90
- isOpen.value = true
91
- emit('open')
92
-
93
- // Calculate position on next tick
94
- setTimeout(() => {
95
- updateMenuPosition()
96
- }, 0)
97
- }
98
-
99
- const closeDropdown = () => {
100
- isOpen.value = false
101
- emit('close')
102
- }
103
-
104
- const updateMenuPosition = () => {
105
- if (!dropdownRef.value || !dropdownMenuRef.value) return
106
-
107
- const triggerRect = dropdownRef.value.getBoundingClientRect()
108
- const menuRect = dropdownMenuRef.value.getBoundingClientRect()
109
-
110
- let top = 0
111
- let left = 0
112
-
113
- switch (props.placement) {
114
- case 'bottom-left':
115
- top = triggerRect.bottom + 8
116
- left = triggerRect.left
117
- break
118
- case 'bottom-right':
119
- top = triggerRect.bottom + 8
120
- left = triggerRect.right - menuRect.width
121
- break
122
- case 'top-left':
123
- top = triggerRect.top - menuRect.height - 8
124
- left = triggerRect.left
125
- break
126
- case 'top-right':
127
- top = triggerRect.top - menuRect.height - 8
128
- left = triggerRect.right - menuRect.width
129
- break
130
- }
131
-
132
- menuStyles.value = {
133
- top: `${top}px`,
134
- left: `${left}px`
135
- }
136
- }
137
-
138
- const handleItemClick = (item: DropdownItem) => {
139
- if (item.disabled) return
140
-
141
- emit('select', item)
142
-
143
- if (props.closeOnClick) {
144
- closeDropdown()
145
- }
146
- }
147
-
148
- const handleMenuClick = (event: MouseEvent) => {
149
- // Prevent closing when clicking inside menu (unless on an item)
150
- event.stopPropagation()
151
- }
152
-
153
- const handleClickOutside = (event: MouseEvent) => {
154
- if (!dropdownRef.value || !dropdownMenuRef.value) return
155
-
156
- const target = event.target as Node
157
- if (!dropdownRef.value.contains(target) && !dropdownMenuRef.value.contains(target)) {
158
- closeDropdown()
159
- }
160
- }
161
-
162
- onMounted(() => {
163
- document.addEventListener('click', handleClickOutside)
164
- window.addEventListener('scroll', updateMenuPosition, true)
165
- window.addEventListener('resize', updateMenuPosition)
166
- })
167
-
168
- onUnmounted(() => {
169
- document.removeEventListener('click', handleClickOutside)
170
- window.removeEventListener('scroll', updateMenuPosition, true)
171
- window.removeEventListener('resize', updateMenuPosition)
172
- })
173
- </script>
174
-
175
- <style scoped>
176
- .dropdown {
177
- position: relative;
178
- display: inline-block;
179
- }
180
-
181
- .dropdown--disabled {
182
- opacity: 0.5;
183
- cursor: not-allowed;
184
- }
185
-
186
- .dropdown__trigger {
187
- cursor: pointer;
188
- }
189
-
190
- .dropdown__button {
191
- padding: 0.5rem 1rem;
192
- background: white;
193
- border: 1px solid #d1d5db;
194
- border-radius: 6px;
195
- font-size: 0.875rem;
196
- font-weight: 500;
197
- color: #374151;
198
- cursor: pointer;
199
- transition: all 0.2s;
200
- }
201
-
202
- .dropdown__button:hover {
203
- background: #f9fafb;
204
- border-color: #9ca3af;
205
- }
206
-
207
- .dropdown__menu {
208
- position: fixed;
209
- z-index: 1000;
210
- min-width: 200px;
211
- background: white;
212
- border: 1px solid #e5e7eb;
213
- border-radius: 8px;
214
- box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
215
- overflow: hidden;
216
- }
217
-
218
- .dropdown__header,
219
- .dropdown__footer {
220
- padding: 0.75rem 1rem;
221
- border-bottom: 1px solid #e5e7eb;
222
- background: #f9fafb;
223
- }
224
-
225
- .dropdown__footer {
226
- border-top: 1px solid #e5e7eb;
227
- border-bottom: none;
228
- }
229
-
230
- .dropdown__content {
231
- padding: 0.5rem 0;
232
- max-height: 300px;
233
- overflow-y: auto;
234
- }
235
-
236
- .dropdown__item {
237
- width: 100%;
238
- display: flex;
239
- align-items: center;
240
- gap: 0.75rem;
241
- padding: 0.625rem 1rem;
242
- border: none;
243
- background: transparent;
244
- text-align: left;
245
- font-size: 0.875rem;
246
- color: #374151;
247
- cursor: pointer;
248
- transition: background-color 0.15s;
249
- }
250
-
251
- .dropdown__item:hover {
252
- background: #f3f4f6;
253
- }
254
-
255
- .dropdown__item:active {
256
- background: #e5e7eb;
257
- }
258
-
259
- .dropdown__item--disabled {
260
- color: #9ca3af;
261
- cursor: not-allowed;
262
- opacity: 0.5;
263
- }
264
-
265
- .dropdown__item--disabled:hover {
266
- background: transparent;
267
- }
268
-
269
- .dropdown__item-icon {
270
- font-size: 1.125rem;
271
- flex-shrink: 0;
272
- }
273
-
274
- .dropdown__item-label {
275
- flex: 1;
276
- }
277
-
278
- .dropdown__divider {
279
- height: 1px;
280
- margin: 0.5rem 0;
281
- background: #e5e7eb;
282
- }
283
-
284
- /* Transitions */
285
- .dropdown-fade-enter-active,
286
- .dropdown-fade-leave-active {
287
- transition: opacity 0.15s ease, transform 0.15s ease;
288
- }
289
-
290
- .dropdown-fade-enter-from,
291
- .dropdown-fade-leave-to {
292
- opacity: 0;
293
- transform: translateY(-8px);
294
- }
295
-
296
- /* Scrollbar styling */
297
- .dropdown__content::-webkit-scrollbar {
298
- width: 6px;
299
- }
300
-
301
- .dropdown__content::-webkit-scrollbar-track {
302
- background: #f1f1f1;
303
- border-radius: 3px;
304
- }
305
-
306
- .dropdown__content::-webkit-scrollbar-thumb {
307
- background: #d1d5db;
308
- border-radius: 3px;
309
- }
310
-
311
- .dropdown__content::-webkit-scrollbar-thumb:hover {
312
- background: #9ca3af;
313
- }
314
- </style>
@@ -1,14 +0,0 @@
1
- export interface DropdownItem {
2
- label: string
3
- value: string
4
- icon?: string
5
- disabled?: boolean
6
- divider?: boolean
7
- }
8
-
9
- export interface DropdownProps {
10
- items?: DropdownItem[]
11
- placement?: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right'
12
- closeOnClick?: boolean
13
- disabled?: boolean
14
- }
@@ -1,189 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3'
2
- import EmptyState from './EmptyState.vue'
3
-
4
- const meta = {
5
- title: 'Components/EmptyState',
6
- component: EmptyState,
7
- tags: ['autodocs'],
8
- argTypes: {
9
- title: {
10
- control: 'text',
11
- description: 'Empty state title'
12
- },
13
- description: {
14
- control: 'text',
15
- description: 'Empty state description'
16
- },
17
- icon: {
18
- control: 'text',
19
- description: 'Icon or emoji to display'
20
- },
21
- actionText: {
22
- control: 'text',
23
- description: 'Action button text'
24
- },
25
- actionVariant: {
26
- control: 'select',
27
- options: ['primary', 'secondary'],
28
- description: 'Action button variant'
29
- },
30
- size: {
31
- control: 'select',
32
- options: ['small', 'medium', 'large'],
33
- description: 'Empty state size'
34
- },
35
- onAction: { action: 'action-clicked' }
36
- },
37
- args: {
38
- size: 'medium',
39
- actionVariant: 'primary'
40
- }
41
- } satisfies Meta<typeof EmptyState>
42
-
43
- export default meta
44
- type Story = StoryObj<typeof meta>
45
-
46
- export const Default: Story = {
47
- args: {
48
- title: 'No items found',
49
- description: 'Get started by creating a new item',
50
- icon: '📭'
51
- }
52
- }
53
-
54
- export const WithAction: Story = {
55
- args: {
56
- title: 'No projects yet',
57
- description: 'Create your first project to get started',
58
- icon: '📁',
59
- actionText: 'Create Project'
60
- }
61
- }
62
-
63
- export const NoData: Story = {
64
- args: {
65
- title: 'No data available',
66
- description: 'There is no data to display at this time',
67
- icon: '📊'
68
- }
69
- }
70
-
71
- export const NoResults: Story = {
72
- args: {
73
- title: 'No results found',
74
- description: 'Try adjusting your search or filter to find what you\'re looking for',
75
- icon: '🔍',
76
- actionText: 'Clear Filters',
77
- actionVariant: 'secondary'
78
- }
79
- }
80
-
81
- export const EmptyInbox: Story = {
82
- args: {
83
- title: 'Inbox Zero!',
84
- description: 'You\'ve read all your messages. Great job!',
85
- icon: '✅'
86
- }
87
- }
88
-
89
- export const Small: Story = {
90
- args: {
91
- title: 'No items',
92
- description: 'Add your first item',
93
- icon: '➕',
94
- actionText: 'Add Item',
95
- size: 'small'
96
- }
97
- }
98
-
99
- export const Large: Story = {
100
- args: {
101
- title: 'Welcome to your dashboard',
102
- description: 'Get started by creating your first project. You can add team members, set goals, and track progress all in one place.',
103
- icon: '🎉',
104
- actionText: 'Get Started',
105
- size: 'large'
106
- }
107
- }
108
-
109
- export const CustomIcon: Story = {
110
- args: {
111
- title: 'No notifications',
112
- description: 'You\'re all caught up!',
113
- icon: '🔔'
114
- }
115
- }
116
-
117
- export const ErrorState: Story = {
118
- args: {
119
- title: 'Something went wrong',
120
- description: 'We couldn\'t load your data. Please try again.',
121
- icon: '⚠️',
122
- actionText: 'Retry',
123
- actionVariant: 'primary'
124
- }
125
- }
126
-
127
- export const WithCustomSlots: Story = {
128
- render: (args: any) => ({
129
- components: { EmptyState },
130
- setup() {
131
- return { args }
132
- },
133
- template: `
134
- <EmptyState v-bind="args">
135
- <template #icon>
136
- <div style="font-size: 4rem;">🚀</div>
137
- </template>
138
- <template #title>
139
- <h2 style="color: #667eea;">Custom Title Slot</h2>
140
- </template>
141
- <template #description>
142
- <p style="color: #6b7280; font-style: italic;">
143
- You can customize any part of the empty state with slots
144
- </p>
145
- </template>
146
- </EmptyState>
147
- `
148
- })
149
- }
150
-
151
- export const AllSizes: Story = {
152
- render: () => ({
153
- components: { EmptyState },
154
- template: `
155
- <div style="display: flex; flex-direction: column; gap: 3rem;">
156
- <div>
157
- <h3 style="margin-bottom: 1rem;">Small</h3>
158
- <EmptyState
159
- size="small"
160
- title="Small empty state"
161
- description="Compact size for inline usage"
162
- icon="📦"
163
- actionText="Action"
164
- />
165
- </div>
166
- <div>
167
- <h3 style="margin-bottom: 1rem;">Medium</h3>
168
- <EmptyState
169
- size="medium"
170
- title="Medium empty state"
171
- description="Default size for most use cases"
172
- icon="📦"
173
- actionText="Action"
174
- />
175
- </div>
176
- <div>
177
- <h3 style="margin-bottom: 1rem;">Large</h3>
178
- <EmptyState
179
- size="large"
180
- title="Large empty state"
181
- description="Larger size for prominent empty states with more detailed descriptions"
182
- icon="📦"
183
- actionText="Action"
184
- />
185
- </div>
186
- </div>
187
- `
188
- })
189
- }