@polymarbot/nuxt-layer-shadcn-ui 0.1.10 → 0.2.0-w

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 (101) hide show
  1. package/app/assets/styles/colors.css +10 -10
  2. package/app/components/ui/Accordion/index.stories.ts +60 -56
  3. package/app/components/ui/Accordion/index.vue +1 -1
  4. package/app/components/ui/AdminLayout/SidebarMenus.vue +0 -2
  5. package/app/components/ui/AdminLayout/index.stories.ts +9 -8
  6. package/app/components/ui/Alert/index.stories.ts +28 -26
  7. package/app/components/ui/Alert/index.vue +6 -6
  8. package/app/components/ui/Alert/types.ts +2 -1
  9. package/app/components/ui/AlertDialog/index.stories.ts +85 -50
  10. package/app/components/ui/AsyncDataTable/index.stories.ts +53 -36
  11. package/app/components/ui/Avatar/index.stories.ts +56 -51
  12. package/app/components/ui/Avatar/index.vue +1 -1
  13. package/app/components/ui/Avatar/types.ts +5 -2
  14. package/app/components/ui/Badge/index.stories.ts +41 -41
  15. package/app/components/ui/Badge/index.vue +1 -1
  16. package/app/components/ui/Badge/types.ts +3 -1
  17. package/app/components/ui/Breadcrumb/index.stories.ts +48 -37
  18. package/app/components/ui/Breadcrumb/index.vue +1 -1
  19. package/app/components/ui/Button/index.stories.ts +94 -90
  20. package/app/components/ui/Button/index.vue +1 -1
  21. package/app/components/ui/Button/types.ts +4 -1
  22. package/app/components/ui/ButtonGroup/index.stories.ts +61 -49
  23. package/app/components/ui/Card/index.stories.ts +55 -47
  24. package/app/components/ui/Card/index.vue +1 -1
  25. package/app/components/ui/Checkbox/index.stories.ts +69 -46
  26. package/app/components/ui/Checkbox/index.vue +1 -1
  27. package/app/components/ui/CopyButton/index.stories.ts +89 -31
  28. package/app/components/ui/DataTable/index.stories.ts +218 -168
  29. package/app/components/ui/DataTable/index.vue +1 -1
  30. package/app/components/ui/DatePicker/index.stories.ts +131 -37
  31. package/app/components/ui/DateRangePicker/index.stories.ts +107 -33
  32. package/app/components/ui/Divider/index.stories.ts +46 -24
  33. package/app/components/ui/Divider/index.vue +1 -1
  34. package/app/components/ui/Drawer/index.stories.ts +131 -81
  35. package/app/components/ui/Drawer/index.vue +1 -1
  36. package/app/components/ui/Drawer/types.ts +1 -1
  37. package/app/components/ui/Dropdown/index.stories.ts +134 -89
  38. package/app/components/ui/Dropdown/index.vue +5 -1
  39. package/app/components/ui/Dropdown/types.ts +1 -1
  40. package/app/components/ui/FormItem/index.stories.ts +87 -43
  41. package/app/components/ui/FormItem/index.vue +1 -1
  42. package/app/components/ui/Help/index.stories.ts +46 -35
  43. package/app/components/ui/Icon/index.stories.ts +41 -43
  44. package/app/components/ui/Input/index.stories.ts +95 -41
  45. package/app/components/ui/Input/index.vue +1 -1
  46. package/app/components/ui/InputCurrency/index.stories.ts +89 -49
  47. package/app/components/ui/InputNumber/index.stories.ts +93 -29
  48. package/app/components/ui/InputNumber/index.vue +1 -1
  49. package/app/components/ui/InputOtp/index.stories.ts +6 -7
  50. package/app/components/ui/InputOtp/index.vue +1 -1
  51. package/app/components/ui/InputPercent/index.stories.ts +6 -7
  52. package/app/components/ui/InputRange/index.stories.ts +6 -7
  53. package/app/components/ui/Loading/index.stories.ts +19 -19
  54. package/app/components/ui/Markdown/index.stories.ts +7 -10
  55. package/app/components/ui/Modal/index.stories.ts +135 -80
  56. package/app/components/ui/Modal/index.vue +1 -1
  57. package/app/components/ui/Modal/types.ts +1 -1
  58. package/app/components/ui/ModalContent/index.stories.ts +54 -26
  59. package/app/components/ui/ModalContent/index.vue +2 -2
  60. package/app/components/ui/PageCard/index.stories.ts +177 -67
  61. package/app/components/ui/Pagination/index.stories.ts +68 -51
  62. package/app/components/ui/Pagination/index.vue +2 -2
  63. package/app/components/ui/Popover/index.stories.ts +47 -45
  64. package/app/components/ui/Popover/index.vue +1 -1
  65. package/app/components/ui/Qrcode/index.stories.ts +42 -34
  66. package/app/components/ui/RadioCardGroup/index.stories.ts +23 -32
  67. package/app/components/ui/RadioCardGroup/index.vue +1 -1
  68. package/app/components/ui/RadioGroup/index.stories.ts +123 -0
  69. package/app/components/ui/RadioGroup/index.vue +73 -0
  70. package/app/components/ui/RadioGroup/types.ts +13 -0
  71. package/app/components/ui/ScrollArea/index.stories.ts +69 -37
  72. package/app/components/ui/ScrollArea/index.vue +1 -1
  73. package/app/components/ui/SearchSelect/index.stories.ts +104 -66
  74. package/app/components/ui/Select/index.stories.ts +152 -98
  75. package/app/components/ui/Select/index.vue +3 -3
  76. package/app/components/ui/Skeleton/index.stories.ts +27 -30
  77. package/app/components/ui/Skeleton/index.vue +1 -1
  78. package/app/components/ui/Slider/index.stories.ts +73 -31
  79. package/app/components/ui/Slider/index.vue +1 -1
  80. package/app/components/ui/Surface/index.stories.ts +47 -21
  81. package/app/components/ui/Surface/index.vue +39 -28
  82. package/app/components/ui/Surface/types.ts +2 -2
  83. package/app/components/ui/Switch/index.stories.ts +6 -7
  84. package/app/components/ui/Switch/index.vue +1 -1
  85. package/app/components/ui/Tabs/index.stories.ts +103 -61
  86. package/app/components/ui/Tabs/index.vue +1 -1
  87. package/app/components/ui/Tag/index.stories.ts +42 -25
  88. package/app/components/ui/Tag/index.vue +39 -28
  89. package/app/components/ui/Tag/types.ts +2 -2
  90. package/app/components/ui/Textarea/index.stories.ts +73 -9
  91. package/app/components/ui/Textarea/index.vue +1 -1
  92. package/app/components/ui/Toast/index.stories.ts +71 -18
  93. package/app/components/ui/Toast/index.vue +1 -1
  94. package/app/components/ui/Tooltip/index.stories.ts +45 -38
  95. package/app/components/ui/Tooltip/index.vue +1 -1
  96. package/app/components/ui/WebLink/index.stories.ts +76 -41
  97. package/app/components/ui/WebLink/index.vue +1 -1
  98. package/package.json +2 -2
  99. package/app/components/ui/Radio/index.stories.ts +0 -71
  100. package/app/components/ui/Radio/index.vue +0 -10
  101. package/app/components/ui/Radio/types.ts +0 -3
@@ -1,9 +1,6 @@
1
1
  import type { Meta, StoryObj } from '@storybook/vue3'
2
2
  import type { DataTableColumn } from './types'
3
- import DataTableRaw from './index.vue'
4
-
5
- // Cast generic component for Storybook compatibility
6
- const DataTable = DataTableRaw as any
3
+ import DataTable from './index.vue'
7
4
 
8
5
  interface User {
9
6
  id: number
@@ -30,37 +27,122 @@ const basicColumns: DataTableColumn[] = [
30
27
  { field: 'status', title: 'Status', width: '100px' },
31
28
  ]
32
29
 
30
+ const sortableColumns: DataTableColumn[] = [
31
+ { field: 'name', title: 'Name', width: '120px', sortable: true },
32
+ { field: 'email', title: 'Email', minWidth: '200px' },
33
+ { field: 'role', title: 'Role', width: '100px', sortable: true },
34
+ { field: 'amount', title: 'Amount', width: '120px', type: 'currency', sortable: true },
35
+ { field: 'createdAt', title: 'Created', width: '140px', type: 'date', sortable: true },
36
+ ]
37
+
38
+ const typeColumns: DataTableColumn[] = [
39
+ { field: 'name', title: 'Name', width: '120px' },
40
+ { field: 'amount', title: 'Amount', width: '120px', type: 'currency' },
41
+ { field: 'createdAt', title: 'Date', width: '140px', type: 'date' },
42
+ { field: 'status', title: 'Empty', width: '100px', type: 'empty' },
43
+ ]
44
+
45
+ const slotColumns: DataTableColumn[] = [
46
+ { field: 'name', title: 'Name', width: '120px' },
47
+ { field: 'email', title: 'Email', minWidth: '200px' },
48
+ { field: 'status', title: 'Status', width: '120px' },
49
+ { field: 'amount', title: 'Amount', width: '120px' },
50
+ ]
51
+
52
+ const frozenColumns: DataTableColumn[] = [
53
+ { field: 'name', title: 'Name', width: '120px', fixed: 'left' },
54
+ { field: 'email', title: 'Email', width: '250px', fixed: 'left' },
55
+ { field: 'role', title: 'Role', width: '150px' },
56
+ { field: 'status', title: 'Status', width: '150px' },
57
+ { field: 'amount', title: 'Amount', width: '150px' },
58
+ { field: 'createdAt', title: 'Created', width: '180px', type: 'date' },
59
+ { field: 'id', title: 'Actions', width: '100px', fixed: 'right' },
60
+ ]
61
+
33
62
  const meta = {
34
63
  title: 'UI/DataTable',
35
- component: DataTable,
64
+ component: DataTable as any,
36
65
  argTypes: {
66
+ selectionMode: { control: 'select', options: [ undefined, 'single', 'multiple' ]},
37
67
  loading: { control: 'boolean' },
68
+ sortBy: { control: 'text' },
69
+ sortOrder: { control: 'select', options: [ null, 1, -1 ]},
38
70
  },
39
71
  args: {
72
+ selectionMode: undefined,
40
73
  loading: false,
74
+ sortBy: null,
75
+ sortOrder: null,
41
76
  },
77
+ render: args => ({
78
+ components: { DataTable: DataTable as any },
79
+ setup: () => ({ args, data: sampleData, basicColumns }),
80
+ template: `
81
+ <div class="w-full">
82
+ <DataTable :data="data" :columns="basicColumns" v-bind="args" />
83
+ </div>
84
+ `,
85
+ }),
42
86
  } satisfies Meta
43
87
 
44
88
  export default meta
45
89
  type Story = StoryObj<typeof meta>
46
90
 
47
- export const Default: Story = {
48
- render: args => ({
49
- components: { DataTable },
91
+ export const Default: Story = {}
92
+
93
+ export const SingleSelection: Story = {
94
+ render: () => ({
95
+ components: { DataTable: DataTable as any },
96
+ setup () {
97
+ const selection = ref<User | null>(null)
98
+ return { data: sampleData, basicColumns, selection }
99
+ },
100
+ template: `
101
+ <div class="w-full">
102
+ <DataTable
103
+ :data="data"
104
+ :columns="basicColumns"
105
+ selectionMode="single"
106
+ v-model:selection="selection"
107
+ />
108
+ <div class="mt-2 text-sm text-muted-foreground">
109
+ Selected: {{ selection?.name ?? 'none' }}
110
+ </div>
111
+ </div>
112
+ `,
113
+ }),
114
+ }
115
+
116
+ export const MultipleSelection: Story = {
117
+ render: () => ({
118
+ components: { DataTable: DataTable as any },
119
+ setup () {
120
+ const selection = ref<User[]>([])
121
+ return { data: sampleData, basicColumns, selection }
122
+ },
123
+ template: `
124
+ <div class="w-full">
125
+ <DataTable
126
+ :data="data"
127
+ :columns="basicColumns"
128
+ selectionMode="multiple"
129
+ v-model:selection="selection"
130
+ />
131
+ <div class="mt-2 text-sm text-muted-foreground">
132
+ Selected: {{ selection.length > 0 ? selection.map(r => r.name).join(', ') : 'none' }}
133
+ </div>
134
+ </div>
135
+ `,
136
+ }),
137
+ }
138
+
139
+ export const Sortable: Story = {
140
+ render: () => ({
141
+ components: { DataTable: DataTable as any },
50
142
  setup () {
51
- const singleSelection = ref(null)
52
- const multipleSelection = ref([])
53
143
  const sortBy = ref<string | null>(null)
54
144
  const sortOrder = ref<number | null>(null)
55
145
 
56
- const sortableColumns: DataTableColumn[] = [
57
- { field: 'name', title: 'Name', width: '120px', sortable: true },
58
- { field: 'email', title: 'Email', minWidth: '200px' },
59
- { field: 'role', title: 'Role', width: '100px', sortable: true },
60
- { field: 'amount', title: 'Amount', width: '120px', type: 'currency', sortable: true },
61
- { field: 'createdAt', title: 'Created', width: '140px', type: 'date', sortable: true },
62
- ]
63
-
64
146
  const sortedData = computed(() => {
65
147
  if (!sortBy.value || !sortOrder.value) return sampleData
66
148
  return [ ...sampleData ].sort((a, b) => {
@@ -72,159 +154,127 @@ export const Default: Story = {
72
154
  })
73
155
  })
74
156
 
75
- const typeColumns: DataTableColumn[] = [
76
- { field: 'name', title: 'Name', width: '120px' },
77
- { field: 'amount', title: 'Amount', width: '120px', type: 'currency' },
78
- { field: 'createdAt', title: 'Date', width: '140px', type: 'date' },
79
- { field: 'status', title: 'Empty', width: '100px', type: 'empty' },
80
- ]
81
-
82
- const slotColumns: DataTableColumn[] = [
83
- { field: 'name', title: 'Name', width: '120px' },
84
- { field: 'email', title: 'Email', minWidth: '200px' },
85
- { field: 'status', title: 'Status', width: '120px' },
86
- { field: 'amount', title: 'Amount', width: '120px' },
87
- ]
88
-
89
- const frozenColumns: DataTableColumn[] = [
90
- { field: 'name', title: 'Name', width: '120px', fixed: 'left' },
91
- { field: 'email', title: 'Email', width: '250px', fixed: 'left' },
92
- { field: 'role', title: 'Role', width: '150px' },
93
- { field: 'status', title: 'Status', width: '150px' },
94
- { field: 'amount', title: 'Amount', width: '150px', type: 'currency' },
95
- { field: 'createdAt', title: 'Created', width: '180px', type: 'date' },
96
- { field: 'id', title: 'Actions', width: '100px', fixed: 'right' },
97
- ]
98
-
99
- return {
100
- args,
101
- data: sampleData,
102
- basicColumns,
103
- sortableColumns,
104
- typeColumns,
105
- slotColumns,
106
- frozenColumns,
107
- singleSelection,
108
- multipleSelection,
109
- sortBy,
110
- sortOrder,
111
- sortedData,
112
- }
157
+ return { sortableColumns, sortBy, sortOrder, sortedData }
113
158
  },
114
159
  template: `
115
- <div class="w-full space-y-10">
116
- <!-- Controlled -->
117
- <section>
118
- <h3 class="mb-4 text-lg font-medium">Controlled</h3>
119
- <DataTable :data="data" :columns="basicColumns" v-bind="args" />
120
- </section>
121
-
122
- <!-- Single Selection -->
123
- <section>
124
- <h3 class="mb-4 text-lg font-medium">Single Selection</h3>
125
- <DataTable
126
- :data="data"
127
- :columns="basicColumns"
128
- selectionMode="single"
129
- v-model:selection="singleSelection"
130
- />
131
- <div class="mt-2 text-sm text-muted-foreground">
132
- Selected: {{ singleSelection?.name ?? 'none' }}
133
- </div>
134
- </section>
135
-
136
- <!-- Multiple Selection -->
137
- <section>
138
- <h3 class="mb-4 text-lg font-medium">Multiple Selection</h3>
139
- <DataTable
140
- :data="data"
141
- :columns="basicColumns"
142
- selectionMode="multiple"
143
- v-model:selection="multipleSelection"
144
- />
145
- <div class="mt-2 text-sm text-muted-foreground">
146
- Selected: {{ multipleSelection.length > 0 ? multipleSelection.map(r => r.name).join(', ') : 'none' }}
147
- </div>
148
- </section>
149
-
150
- <!-- Sortable -->
151
- <section>
152
- <h3 class="mb-4 text-lg font-medium">Sortable Columns</h3>
153
- <DataTable
154
- :data="sortedData"
155
- :columns="sortableColumns"
156
- v-model:sortBy="sortBy"
157
- v-model:sortOrder="sortOrder"
158
- />
159
- <div class="mt-2 text-sm text-muted-foreground">
160
- Sort: {{ sortBy ?? 'none' }} / {{ sortOrder ?? 'none' }}
161
- </div>
162
- </section>
163
-
164
- <!-- Column Types -->
165
- <section>
166
- <h3 class="mb-4 text-lg font-medium">Column Types (text, currency, date, empty)</h3>
167
- <DataTable :data="data" :columns="typeColumns" />
168
- </section>
169
-
170
- <!-- Custom Slots -->
171
- <section>
172
- <h3 class="mb-4 text-lg font-medium">Custom Cell Slots</h3>
173
- <DataTable :data="data" :columns="slotColumns">
174
- <template #status="{ value }">
175
- <span
176
- :class="[
177
- 'inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium',
178
- value === 'active'
179
- ? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200'
180
- : 'bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-200',
181
- ]"
182
- >
183
- {{ value }}
184
- </span>
185
- </template>
186
- <template #amount="{ value }">
187
- <span class="font-mono font-medium">\${{ Number(value).toFixed(2) }}</span>
188
- </template>
189
- </DataTable>
190
- </section>
191
-
192
- <!-- Empty State -->
193
- <section>
194
- <h3 class="mb-4 text-lg font-medium">Empty State</h3>
195
- <DataTable :data="[]" :columns="basicColumns" />
196
- </section>
197
-
198
- <!-- Footer Slot -->
199
- <section>
200
- <h3 class="mb-4 text-lg font-medium">Footer Slot</h3>
201
- <DataTable :data="data" :columns="slotColumns">
202
- <template #footer>
203
- <tr class="h-12 border-t text-sm font-medium">
204
- <td class="px-4">Total</td>
205
- <td class="px-4" colspan="2"></td>
206
- <td class="px-4 font-mono">\${{ data.reduce((sum, r) => sum + r.amount, 0).toFixed(2) }}</td>
207
- </tr>
208
- </template>
209
- </DataTable>
210
- </section>
211
-
212
- <!-- Frozen Columns -->
213
- <section>
214
- <h3 class="mb-4 text-lg font-medium">Frozen Columns (scroll horizontally)</h3>
215
- <div class="max-w-[600px]">
216
- <DataTable
217
- :data="data"
218
- :columns="frozenColumns"
219
- selectionMode="multiple"
220
- v-model:selection="multipleSelection"
160
+ <div class="w-full">
161
+ <DataTable
162
+ :data="sortedData"
163
+ :columns="sortableColumns"
164
+ v-model:sortBy="sortBy"
165
+ v-model:sortOrder="sortOrder"
166
+ />
167
+ <div class="mt-2 text-sm text-muted-foreground">
168
+ Sort: {{ sortBy ?? 'none' }} / {{ sortOrder ?? 'none' }}
169
+ </div>
170
+ </div>
171
+ `,
172
+ }),
173
+ }
174
+
175
+ export const ColumnTypes: Story = {
176
+ render: () => ({
177
+ components: { DataTable: DataTable as any },
178
+ setup: () => ({ data: sampleData, typeColumns }),
179
+ template: `
180
+ <div class="w-full">
181
+ <DataTable :data="data" :columns="typeColumns" />
182
+ </div>
183
+ `,
184
+ }),
185
+ }
186
+
187
+ export const CustomSlots: Story = {
188
+ render: () => ({
189
+ components: { DataTable: DataTable as any },
190
+ setup: () => ({ data: sampleData, slotColumns }),
191
+ template: `
192
+ <div class="w-full">
193
+ <DataTable :data="data" :columns="slotColumns">
194
+ <template #status="{ value }">
195
+ <span
196
+ :class="[
197
+ 'inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium',
198
+ value === 'active'
199
+ ? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200'
200
+ : 'bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-200',
201
+ ]"
221
202
  >
222
- <template #id>
223
- <button class="text-sm text-primary underline">Edit</button>
224
- </template>
225
- </DataTable>
226
- </div>
227
- </section>
203
+ {{ value }}
204
+ </span>
205
+ </template>
206
+ <template #amount="{ value }">
207
+ <span class="font-mono font-medium">\${{ Number(value).toFixed(2) }}</span>
208
+ </template>
209
+ </DataTable>
210
+ </div>
211
+ `,
212
+ }),
213
+ }
214
+
215
+ export const EmptyState: Story = {
216
+ render: () => ({
217
+ components: { DataTable: DataTable as any },
218
+ setup: () => ({ basicColumns }),
219
+ template: `
220
+ <div class="w-full">
221
+ <DataTable :data="[]" :columns="basicColumns" />
222
+ </div>
223
+ `,
224
+ }),
225
+ }
226
+
227
+ export const FooterSlot: Story = {
228
+ render: () => ({
229
+ components: { DataTable: DataTable as any },
230
+ setup: () => ({ data: sampleData, slotColumns }),
231
+ template: `
232
+ <div class="w-full">
233
+ <DataTable :data="data" :columns="slotColumns">
234
+ <template #footer>
235
+ <tr class="h-12 border-t text-sm font-medium">
236
+ <td class="px-4">Total</td>
237
+ <td class="px-4" colspan="2"></td>
238
+ <td class="px-4 font-mono">\${{ data.reduce((sum, r) => sum + r.amount, 0).toFixed(2) }}</td>
239
+ </tr>
240
+ </template>
241
+ </DataTable>
242
+ </div>
243
+ `,
244
+ }),
245
+ }
246
+
247
+ export const FrozenColumns: Story = {
248
+ render: () => ({
249
+ components: { DataTable: DataTable as any },
250
+ setup () {
251
+ const selection = ref<User[]>([])
252
+ return { data: sampleData, frozenColumns, selection }
253
+ },
254
+ template: `
255
+ <div class="max-w-[600px]">
256
+ <DataTable
257
+ :data="data"
258
+ :columns="frozenColumns"
259
+ selectionMode="multiple"
260
+ v-model:selection="selection"
261
+ >
262
+ <template #id>
263
+ <button class="text-sm text-primary underline">Edit</button>
264
+ </template>
265
+ </DataTable>
266
+ </div>
267
+ `,
268
+ }),
269
+ }
270
+
271
+ export const Loading: Story = {
272
+ render: () => ({
273
+ components: { DataTable: DataTable as any },
274
+ setup: () => ({ data: sampleData, basicColumns }),
275
+ template: `
276
+ <div class="w-full">
277
+ <DataTable :data="data" :columns="basicColumns" loading />
228
278
  </div>
229
279
  `,
230
280
  }),
@@ -10,7 +10,7 @@ import {
10
10
  TableHead,
11
11
  TableHeader,
12
12
  TableRow,
13
- } from '@polymarbot/nuxt-layer-shadcn-ui/app/components/shadcn/table'
13
+ } from '../../shadcn/table'
14
14
  import type {
15
15
  DataTableColumn,
16
16
  DataTableProps,
@@ -1,69 +1,163 @@
1
1
  import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import type { DatePickerType } from './types'
2
3
  import DatePicker from './index.vue'
3
4
 
5
+ const types: DatePickerType[] = [ 'date', 'month', 'year' ]
6
+
4
7
  const meta = {
5
8
  title: 'UI/DatePicker',
6
9
  component: DatePicker,
7
10
  argTypes: {
11
+ modelValue: { control: 'date' },
12
+ type: { control: 'select', options: types },
8
13
  showTime: { control: 'boolean' },
9
14
  disabled: { control: 'boolean' },
15
+ readonly: { control: 'boolean' },
16
+ placeholder: { control: 'text' },
17
+ minDate: { control: 'date' },
18
+ maxDate: { control: 'date' },
19
+ valueFormat: { control: 'text' },
20
+ autoApply: { control: 'boolean' },
21
+ class: { control: 'text' },
10
22
  },
11
23
  args: {
24
+ modelValue: null,
25
+ type: 'date',
12
26
  showTime: false,
13
27
  disabled: false,
28
+ readonly: false,
29
+ placeholder: '',
30
+ minDate: undefined,
31
+ maxDate: undefined,
32
+ valueFormat: '',
33
+ autoApply: false,
34
+ class: '',
14
35
  },
36
+ render: args => ({
37
+ components: { DatePicker },
38
+ setup () {
39
+ const value = ref<Date | string | null>(null)
40
+ return { args, value }
41
+ },
42
+ template: `
43
+ <div class="max-w-xs">
44
+ <DatePicker v-model="value" v-bind="args" />
45
+ <div class="mt-2 text-sm text-muted-foreground">Value: {{ value }}</div>
46
+ </div>
47
+ `,
48
+ }),
15
49
  } satisfies Meta<typeof DatePicker>
16
50
 
17
51
  export default meta
18
52
  type Story = StoryObj<typeof meta>
19
53
 
20
- export const Default: Story = {
21
- render: args => ({
54
+ export const Default: Story = {}
55
+
56
+ export const MonthPicker: Story = {
57
+ render: () => ({
22
58
  components: { DatePicker },
23
59
  setup () {
24
- const date = ref<Date | null>(null)
25
- const preselected = ref<Date>(new Date(2025, 5, 15))
26
- const formatted = ref<string | null>(null)
27
60
  const month = ref<Date | null>(null)
61
+ return { month }
62
+ },
63
+ template: `
64
+ <div class="max-w-xs">
65
+ <DatePicker v-model="month" type="month" placeholder="Pick a month" />
66
+ <div class="mt-2 text-sm text-muted-foreground">Value: {{ month }}</div>
67
+ </div>
68
+ `,
69
+ }),
70
+ }
71
+
72
+ export const YearPicker: Story = {
73
+ render: () => ({
74
+ components: { DatePicker },
75
+ setup () {
28
76
  const year = ref<Date | null>(null)
29
- return { args, date, month, year, preselected, formatted }
77
+ return { year }
30
78
  },
31
79
  template: `
32
- <div class="space-y-10 max-w-xs">
33
- <!-- Controlled -->
34
- <section>
35
- <h3 class="mb-4 text-lg font-medium">Controlled</h3>
36
- <DatePicker v-model="date" v-bind="args" />
37
- <div class="mt-2 text-sm text-muted-foreground">Value: {{ date }}</div>
38
- </section>
80
+ <div class="max-w-xs">
81
+ <DatePicker v-model="year" type="year" placeholder="Pick a year" />
82
+ <div class="mt-2 text-sm text-muted-foreground">Value: {{ year }}</div>
83
+ </div>
84
+ `,
85
+ }),
86
+ }
39
87
 
40
- <!-- Month Picker -->
41
- <section>
42
- <h3 class="mb-4 text-lg font-medium">Month Picker</h3>
43
- <DatePicker v-model="month" type="month" placeholder="Pick a month" />
44
- <div class="mt-2 text-sm text-muted-foreground">Value: {{ month }}</div>
45
- </section>
88
+ export const WithTime: Story = {
89
+ render: () => ({
90
+ components: { DatePicker },
91
+ setup () {
92
+ const date = ref<Date | null>(null)
93
+ return { date }
94
+ },
95
+ template: `
96
+ <div class="max-w-xs">
97
+ <DatePicker v-model="date" showTime />
98
+ <div class="mt-2 text-sm text-muted-foreground">Value: {{ date }}</div>
99
+ </div>
100
+ `,
101
+ }),
102
+ }
46
103
 
47
- <!-- Year Picker -->
48
- <section>
49
- <h3 class="mb-4 text-lg font-medium">Year Picker</h3>
50
- <DatePicker v-model="year" type="year" placeholder="Pick a year" />
51
- <div class="mt-2 text-sm text-muted-foreground">Value: {{ year }}</div>
52
- </section>
104
+ export const Preselected: Story = {
105
+ render: () => ({
106
+ components: { DatePicker },
107
+ setup () {
108
+ const preselected = ref<Date>(new Date(2025, 5, 15))
109
+ return { preselected }
110
+ },
111
+ template: `
112
+ <div class="max-w-xs">
113
+ <DatePicker v-model="preselected" />
114
+ <div class="mt-2 text-sm text-muted-foreground">Value: {{ preselected }}</div>
115
+ </div>
116
+ `,
117
+ }),
118
+ }
53
119
 
54
- <!-- Preselected -->
55
- <section>
56
- <h3 class="mb-4 text-lg font-medium">Preselected</h3>
57
- <DatePicker v-model="preselected" />
58
- <div class="mt-2 text-sm text-muted-foreground">Value: {{ preselected }}</div>
59
- </section>
120
+ export const ValueFormat: Story = {
121
+ render: () => ({
122
+ components: { DatePicker },
123
+ setup () {
124
+ const formatted = ref<string | null>(null)
125
+ return { formatted }
126
+ },
127
+ template: `
128
+ <div class="max-w-xs">
129
+ <DatePicker v-model="formatted" valueFormat="yyyy-MM-dd" placeholder="Pick a date" />
130
+ <div class="mt-2 text-sm text-muted-foreground">Value: {{ formatted }}</div>
131
+ </div>
132
+ `,
133
+ }),
134
+ }
135
+
136
+ export const Disabled: Story = {
137
+ render: () => ({
138
+ components: { DatePicker },
139
+ setup () {
140
+ const date = ref<Date>(new Date(2025, 5, 15))
141
+ return { date }
142
+ },
143
+ template: `
144
+ <div class="max-w-xs">
145
+ <DatePicker v-model="date" disabled />
146
+ </div>
147
+ `,
148
+ }),
149
+ }
60
150
 
61
- <!-- Value Format -->
62
- <section>
63
- <h3 class="mb-4 text-lg font-medium">Value Format (yyyy-MM-dd)</h3>
64
- <DatePicker v-model="formatted" valueFormat="yyyy-MM-dd" placeholder="Pick a date" />
65
- <div class="mt-2 text-sm text-muted-foreground">Value: {{ formatted }}</div>
66
- </section>
151
+ export const Readonly: Story = {
152
+ render: () => ({
153
+ components: { DatePicker },
154
+ setup () {
155
+ const date = ref<Date>(new Date(2025, 5, 15))
156
+ return { date }
157
+ },
158
+ template: `
159
+ <div class="max-w-xs">
160
+ <DatePicker v-model="date" readonly />
67
161
  </div>
68
162
  `,
69
163
  }),