@polymarbot/nuxt-layer-shadcn-ui 0.5.4 → 0.6.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.
@@ -28,11 +28,11 @@ const meta = {
28
28
  showTime: false,
29
29
  disabled: false,
30
30
  readonly: false,
31
- placeholder: '',
31
+ placeholder: undefined,
32
32
  minDate: undefined,
33
33
  maxDate: undefined,
34
- valueFormat: '',
35
- autoApply: false,
34
+ valueFormat: undefined,
35
+ autoApply: true,
36
36
  class: '',
37
37
  },
38
38
  render: args => ({
@@ -43,7 +43,7 @@ const meta = {
43
43
  },
44
44
  template: `
45
45
  <div class="max-w-xs">
46
- <DatePicker v-model="value" v-bind="args" />
46
+ <DatePicker v-bind="args" v-model="value" />
47
47
  <div class="mt-2 text-sm text-muted-foreground">Value: {{ value }}</div>
48
48
  </div>
49
49
  `,
@@ -1,48 +1,53 @@
1
1
  import type { Meta, StoryObj } from '@storybook/vue3'
2
- import type { DateRangePickerValue } from './types'
3
2
  import DateRangePicker from './index.vue'
4
3
 
5
4
  const meta = {
6
5
  title: 'UI/DateRangePicker',
7
6
  component: DateRangePicker,
8
7
  argTypes: {
9
- modelValue: { control: 'object' },
8
+ start: { control: 'date' },
9
+ end: { control: 'date' },
10
+ minDate: { control: 'date' },
11
+ maxDate: { control: 'date' },
10
12
  showTime: { control: 'boolean' },
11
13
  disabled: { control: 'boolean' },
12
14
  readonly: { control: 'boolean' },
13
15
  startPlaceholder: { control: 'text' },
14
16
  endPlaceholder: { control: 'text' },
15
- minDate: { control: 'date' },
16
- maxDate: { control: 'date' },
17
17
  maxSpanDays: { control: 'number' },
18
18
  valueFormat: { control: 'text' },
19
19
  autoApply: { control: 'boolean' },
20
20
  class: { control: 'text' },
21
21
  },
22
22
  args: {
23
- modelValue: [ null, null ],
23
+ start: null,
24
+ end: null,
25
+ minDate: undefined,
26
+ maxDate: undefined,
24
27
  showTime: false,
25
28
  disabled: false,
26
29
  readonly: false,
27
- startPlaceholder: '',
28
- endPlaceholder: '',
29
- minDate: undefined,
30
- maxDate: undefined,
30
+ startPlaceholder: undefined,
31
+ endPlaceholder: undefined,
31
32
  maxSpanDays: undefined,
32
- valueFormat: '',
33
- autoApply: false,
33
+ valueFormat: undefined,
34
+ autoApply: true,
34
35
  class: '',
35
36
  },
36
37
  render: args => ({
37
38
  components: { DateRangePicker },
38
39
  setup () {
39
- const range = ref<DateRangePickerValue>([ null, null ])
40
- return { args, range }
40
+ const start = ref<Date | string | null>(args.start ?? null)
41
+ const end = ref<Date | string | null>(args.end ?? null)
42
+ return { args, start, end }
41
43
  },
42
44
  template: `
43
45
  <div class="max-w-lg">
44
- <DateRangePicker v-model="range" v-bind="args" />
45
- <div class="mt-2 text-sm text-muted-foreground">Value: {{ range }}</div>
46
+ <DateRangePicker v-bind="args" v-model:start="start" v-model:end="end" />
47
+ <div class="mt-2 text-sm text-muted-foreground">
48
+ <div>Start: {{ start }}</div>
49
+ <div>End: {{ end }}</div>
50
+ </div>
46
51
  </div>
47
52
  `,
48
53
  }),
@@ -60,20 +65,24 @@ export const WithTime: Story = {
60
65
  ...noControls,
61
66
  docs: {
62
67
  source: {
63
- code: '<DateRangePicker v-model="withTime" showTime />',
68
+ code: '<DateRangePicker v-model:start="start" v-model:end="end" showTime />',
64
69
  },
65
70
  },
66
71
  },
67
72
  render: () => ({
68
73
  components: { DateRangePicker },
69
74
  setup () {
70
- const withTime = ref<DateRangePickerValue>([ null, null ])
71
- return { withTime }
75
+ const start = ref<Date | string | null>(null)
76
+ const end = ref<Date | string | null>(null)
77
+ return { start, end }
72
78
  },
73
79
  template: `
74
80
  <div class="max-w-lg">
75
- <DateRangePicker v-model="withTime" showTime />
76
- <div class="mt-2 text-sm text-muted-foreground">Value: {{ withTime }}</div>
81
+ <DateRangePicker v-model:start="start" v-model:end="end" showTime />
82
+ <div class="mt-2 text-sm text-muted-foreground">
83
+ <div>Start: {{ start }}</div>
84
+ <div>End: {{ end }}</div>
85
+ </div>
77
86
  </div>
78
87
  `,
79
88
  }),
@@ -84,20 +93,24 @@ export const MaxSpanDays: Story = {
84
93
  ...noControls,
85
94
  docs: {
86
95
  source: {
87
- code: '<DateRangePicker v-model="maxSpan" :maxSpanDays="7" />',
96
+ code: '<DateRangePicker v-model:start="start" v-model:end="end" :maxSpanDays="7" />',
88
97
  },
89
98
  },
90
99
  },
91
100
  render: () => ({
92
101
  components: { DateRangePicker },
93
102
  setup () {
94
- const maxSpan = ref<DateRangePickerValue>([ null, null ])
95
- return { maxSpan }
103
+ const start = ref<Date | string | null>(null)
104
+ const end = ref<Date | string | null>(null)
105
+ return { start, end }
96
106
  },
97
107
  template: `
98
108
  <div class="max-w-lg">
99
- <DateRangePicker v-model="maxSpan" :maxSpanDays="7" />
100
- <div class="mt-2 text-sm text-muted-foreground">Value: {{ maxSpan }}</div>
109
+ <DateRangePicker v-model:start="start" v-model:end="end" :maxSpanDays="7" />
110
+ <div class="mt-2 text-sm text-muted-foreground">
111
+ <div>Start: {{ start }}</div>
112
+ <div>End: {{ end }}</div>
113
+ </div>
101
114
  </div>
102
115
  `,
103
116
  }),
@@ -108,23 +121,24 @@ export const Preselected: Story = {
108
121
  ...noControls,
109
122
  docs: {
110
123
  source: {
111
- code: '<DateRangePicker v-model="preselected" />',
124
+ code: '<DateRangePicker v-model:start="start" v-model:end="end" />',
112
125
  },
113
126
  },
114
127
  },
115
128
  render: () => ({
116
129
  components: { DateRangePicker },
117
130
  setup () {
118
- const preselected = ref<DateRangePickerValue>([
119
- new Date(2025, 5, 1),
120
- new Date(2025, 5, 15),
121
- ])
122
- return { preselected }
131
+ const start = ref<Date | string | null>(new Date(2025, 5, 1))
132
+ const end = ref<Date | string | null>(new Date(2025, 5, 15))
133
+ return { start, end }
123
134
  },
124
135
  template: `
125
136
  <div class="max-w-lg">
126
- <DateRangePicker v-model="preselected" />
127
- <div class="mt-2 text-sm text-muted-foreground">Value: {{ preselected }}</div>
137
+ <DateRangePicker v-model:start="start" v-model:end="end" />
138
+ <div class="mt-2 text-sm text-muted-foreground">
139
+ <div>Start: {{ start }}</div>
140
+ <div>End: {{ end }}</div>
141
+ </div>
128
142
  </div>
129
143
  `,
130
144
  }),
@@ -135,22 +149,20 @@ export const Disabled: Story = {
135
149
  ...noControls,
136
150
  docs: {
137
151
  source: {
138
- code: '<DateRangePicker v-model="range" disabled />',
152
+ code: '<DateRangePicker v-model:start="start" v-model:end="end" disabled />',
139
153
  },
140
154
  },
141
155
  },
142
156
  render: () => ({
143
157
  components: { DateRangePicker },
144
158
  setup () {
145
- const range = ref<DateRangePickerValue>([
146
- new Date(2025, 5, 1),
147
- new Date(2025, 5, 15),
148
- ])
149
- return { range }
159
+ const start = ref<Date | string | null>(new Date(2025, 5, 1))
160
+ const end = ref<Date | string | null>(new Date(2025, 5, 15))
161
+ return { start, end }
150
162
  },
151
163
  template: `
152
164
  <div class="max-w-lg">
153
- <DateRangePicker v-model="range" disabled />
165
+ <DateRangePicker v-model:start="start" v-model:end="end" disabled />
154
166
  </div>
155
167
  `,
156
168
  }),
@@ -161,22 +173,20 @@ export const Readonly: Story = {
161
173
  ...noControls,
162
174
  docs: {
163
175
  source: {
164
- code: '<DateRangePicker v-model="range" readonly />',
176
+ code: '<DateRangePicker v-model:start="start" v-model:end="end" readonly />',
165
177
  },
166
178
  },
167
179
  },
168
180
  render: () => ({
169
181
  components: { DateRangePicker },
170
182
  setup () {
171
- const range = ref<DateRangePickerValue>([
172
- new Date(2025, 5, 1),
173
- new Date(2025, 5, 15),
174
- ])
175
- return { range }
183
+ const start = ref<Date | string | null>(new Date(2025, 5, 1))
184
+ const end = ref<Date | string | null>(new Date(2025, 5, 15))
185
+ return { start, end }
176
186
  },
177
187
  template: `
178
188
  <div class="max-w-lg">
179
- <DateRangePicker v-model="range" readonly />
189
+ <DateRangePicker v-model:start="start" v-model:end="end" readonly />
180
190
  </div>
181
191
  `,
182
192
  }),
@@ -1,10 +1,11 @@
1
1
  <script setup lang="ts">
2
- import type { DateRangePickerProps, DateRangePickerValue } from './types'
2
+ import type { DateRangePickerProps } from './types'
3
3
 
4
4
  defineOptions({ inheritAttrs: false })
5
5
 
6
6
  const props = withDefaults(defineProps<DateRangePickerProps>(), {
7
- modelValue: () => [ null, null ],
7
+ start: null,
8
+ end: null,
8
9
  showTime: false,
9
10
  disabled: false,
10
11
  readonly: false,
@@ -19,81 +20,69 @@ const props = withDefaults(defineProps<DateRangePickerProps>(), {
19
20
  })
20
21
 
21
22
  const emit = defineEmits<{
22
- 'update:modelValue': [value: DateRangePickerValue]
23
+ 'update:start': [value: Date | string | null]
24
+ 'update:end': [value: Date | string | null]
23
25
  }>()
24
26
 
25
27
  const T = useTranslations('components.ui.DateRangePicker')
26
28
 
27
- const startDate = ref<Date | string | null>(props.modelValue?.[0] ?? null)
28
- const endDate = ref<Date | string | null>(props.modelValue?.[1] ?? null)
29
-
30
- watch(() => props.modelValue, val => {
31
- startDate.value = val?.[0] ?? null
32
- endDate.value = val?.[1] ?? null
29
+ const start = computed({
30
+ get: () => props.start,
31
+ set: value => emit('update:start', value),
33
32
  })
34
33
 
35
- function emitRange () {
36
- emit('update:modelValue', [ startDate.value, endDate.value ])
37
- }
38
-
39
- function handleStartUpdate (value: Date | string | null) {
40
- startDate.value = value
41
- emitRange()
42
- }
43
-
44
- function handleEndUpdate (value: Date | string | null) {
45
- // If time is disabled, set end time to end of day
46
- if (value instanceof Date && !props.showTime) {
47
- const adjusted = new Date(value)
48
- adjusted.setHours(23, 59, 59, 999)
49
- endDate.value = adjusted
50
- } else {
51
- endDate.value = value
52
- }
53
- emitRange()
54
- }
34
+ const end = computed({
35
+ get: () => props.end,
36
+ set: value => {
37
+ // When time is disabled, normalize end to end of day so range is inclusive
38
+ if (value instanceof Date && !props.showTime) {
39
+ const adjusted = new Date(value)
40
+ adjusted.setHours(23, 59, 59, 999)
41
+ emit('update:end', adjusted)
42
+ } else {
43
+ emit('update:end', value)
44
+ }
45
+ },
46
+ })
55
47
 
56
- // Helper functions for date constraints
57
48
  function addDays (date: Date, days: number): Date {
58
49
  const result = new Date(date)
59
50
  result.setDate(result.getDate() + days)
60
51
  return result
61
52
  }
62
53
 
63
- function toDate (value: Date | string | null): Date | undefined {
54
+ function toDate (value: Date | string | null | undefined): Date | undefined {
64
55
  if (!value) return undefined
65
56
  return value instanceof Date ? value : new Date(value)
66
57
  }
67
58
 
68
- // Start picker constraints
69
59
  const startMinDate = computed(() => {
70
60
  const min = props.minDate
71
- const spanLimit = props.maxSpanDays && endDate.value
72
- ? addDays(toDate(endDate.value)!, -(props.maxSpanDays - 1))
61
+ const spanLimit = props.maxSpanDays && props.end
62
+ ? addDays(toDate(props.end)!, -(props.maxSpanDays - 1))
73
63
  : undefined
74
64
  if (min && spanLimit) return new Date(Math.max(+new Date(min), +spanLimit))
75
65
  return min ?? spanLimit
76
66
  })
77
67
 
78
68
  const startMaxDate = computed(() => {
79
- const end = toDate(endDate.value)
69
+ const endDate = toDate(props.end)
80
70
  const max = props.maxDate
81
- if (end && max) return new Date(Math.min(+end, +new Date(max)))
82
- return end ?? max
71
+ if (endDate && max) return new Date(Math.min(+endDate, +new Date(max)))
72
+ return endDate ?? max
83
73
  })
84
74
 
85
- // End picker constraints
86
75
  const endMinDate = computed(() => {
87
- const start = toDate(startDate.value)
76
+ const startDate = toDate(props.start)
88
77
  const min = props.minDate
89
- if (start && min) return new Date(Math.max(+start, +new Date(min)))
90
- return start ?? min
78
+ if (startDate && min) return new Date(Math.max(+startDate, +new Date(min)))
79
+ return startDate ?? min
91
80
  })
92
81
 
93
82
  const endMaxDate = computed(() => {
94
83
  const max = props.maxDate
95
- const spanLimit = props.maxSpanDays && startDate.value
96
- ? addDays(toDate(startDate.value)!, props.maxSpanDays - 1)
84
+ const spanLimit = props.maxSpanDays && props.start
85
+ ? addDays(toDate(props.start)!, props.maxSpanDays - 1)
97
86
  : undefined
98
87
  if (max && spanLimit) return new Date(Math.min(+new Date(max), +spanLimit))
99
88
  return max ?? spanLimit
@@ -103,7 +92,7 @@ const endMaxDate = computed(() => {
103
92
  <template>
104
93
  <div :class="cn('gap-2 flex items-center', props.class)">
105
94
  <DatePicker
106
- :modelValue="startDate"
95
+ v-model="start"
107
96
  :showTime="showTime"
108
97
  :disabled="disabled"
109
98
  :readonly="readonly"
@@ -113,13 +102,12 @@ const endMaxDate = computed(() => {
113
102
  :valueFormat="valueFormat"
114
103
  :autoApply="autoApply"
115
104
  v-bind="$attrs"
116
- @update:modelValue="handleStartUpdate"
117
105
  />
118
106
  <span class="text-muted-foreground shrink-0">
119
107
  {{ T('to') }}
120
108
  </span>
121
109
  <DatePicker
122
- :modelValue="endDate"
110
+ v-model="end"
123
111
  :showTime="showTime"
124
112
  :disabled="disabled"
125
113
  :readonly="readonly"
@@ -129,7 +117,6 @@ const endMaxDate = computed(() => {
129
117
  :valueFormat="valueFormat"
130
118
  :autoApply="autoApply"
131
119
  v-bind="$attrs"
132
- @update:modelValue="handleEndUpdate"
133
120
  />
134
121
  </div>
135
122
  </template>
@@ -1,12 +1,12 @@
1
1
  import type { DatePickerTimeConfig } from '../DatePicker/types'
2
2
 
3
- export type DateRangePickerValue = [
4
- start: Date | string | null,
5
- end: Date | string | null,
6
- ]
7
-
8
3
  export interface DateRangePickerProps {
9
- modelValue?: DateRangePickerValue
4
+ start?: Date | string | null
5
+ end?: Date | string | null
6
+ /** Minimum selectable date */
7
+ minDate?: Date | string
8
+ /** Maximum selectable date */
9
+ maxDate?: Date | string
10
10
  /** Enable time selection, or pass DatePickerTimeConfig for fine-grained control */
11
11
  showTime?: boolean | DatePickerTimeConfig
12
12
  /** Disable the date range picker */
@@ -17,10 +17,6 @@ export interface DateRangePickerProps {
17
17
  startPlaceholder?: string
18
18
  /** Placeholder for end date input */
19
19
  endPlaceholder?: string
20
- /** Minimum selectable date */
21
- minDate?: Date | string
22
- /** Maximum selectable date */
23
- maxDate?: Date | string
24
20
  /** Maximum span in days between start and end date */
25
21
  maxSpanDays?: number
26
22
  /** v-model output format (e.g. 'yyyy-MM-dd', 'timestamp', 'iso') */
@@ -57,7 +57,7 @@ const meta = {
57
57
  template: `
58
58
  <div>
59
59
  <Button @click="visible = true">Open Drawer</Button>
60
- <Drawer v-model:visible="visible" v-bind="args">
60
+ <Drawer v-bind="args" v-model:visible="visible">
61
61
  <p>This is the drawer content.</p>
62
62
  <Input class="mt-4" placeholder="Try interacting with this input" />
63
63
  </Drawer>
@@ -22,7 +22,7 @@ const meta = {
22
22
  },
23
23
  template: `
24
24
  <div class="max-w-xs">
25
- <InputCurrency v-model="value" v-bind="args" />
25
+ <InputCurrency v-bind="args" v-model="value" />
26
26
  <div class="mt-2 text-sm text-muted-foreground">Value: {{ value }}</div>
27
27
  </div>
28
28
  `,
@@ -31,7 +31,7 @@ const meta = {
31
31
  },
32
32
  template: `
33
33
  <div class="max-w-xs">
34
- <InputNumber v-model="value" v-bind="args" />
34
+ <InputNumber v-bind="args" v-model="value" />
35
35
  <div class="mt-2 text-sm text-muted-foreground">Value: {{ value }}</div>
36
36
  </div>
37
37
  `,
@@ -23,7 +23,7 @@ const meta = {
23
23
  },
24
24
  template: `
25
25
  <div class="space-y-4">
26
- <InputOtp v-model="otp" v-bind="args" />
26
+ <InputOtp v-bind="args" v-model="otp" />
27
27
  <div class="text-sm text-muted-foreground">Value: {{ otp }}</div>
28
28
  </div>
29
29
  `,
@@ -14,7 +14,7 @@ const meta = {
14
14
  },
15
15
  template: `
16
16
  <div class="max-w-xs space-y-4">
17
- <InputPercent v-model="percent" v-bind="args" />
17
+ <InputPercent v-bind="args" v-model="percent" />
18
18
  <div class="text-sm text-muted-foreground">Value: {{ percent }}</div>
19
19
  </div>
20
20
  `,
@@ -28,7 +28,7 @@ const meta = {
28
28
  },
29
29
  template: `
30
30
  <div class="max-w-md">
31
- <InputRange v-model:start="start" v-model:end="end" v-bind="args" />
31
+ <InputRange v-bind="args" v-model:start="start" v-model:end="end" />
32
32
  <div class="mt-2 text-sm text-muted-foreground">Start: {{ start }}, End: {{ end }}</div>
33
33
  </div>
34
34
  `,
@@ -7,7 +7,7 @@ const props = withDefaults(defineProps<InputRangeProps>(), {
7
7
  start: undefined,
8
8
  end: undefined,
9
9
  min: 0,
10
- max: 100,
10
+ max: undefined,
11
11
  })
12
12
 
13
13
  const emit = defineEmits<{
@@ -27,7 +27,7 @@ const end = computed({
27
27
  </script>
28
28
 
29
29
  <template>
30
- <div class="flex items-center gap-2">
30
+ <div class="gap-2 flex items-center">
31
31
  <InputNumber
32
32
  v-model="start"
33
33
  v-bind="$attrs"
@@ -51,7 +51,7 @@ const meta = {
51
51
  template: `
52
52
  <div>
53
53
  <Button @click="visible = true">Open Modal</Button>
54
- <Modal v-model:visible="visible" v-bind="args">
54
+ <Modal v-bind="args" v-model:visible="visible">
55
55
  <p>This is the modal content.</p>
56
56
  <Input class="mt-4" placeholder="Try interacting with this input" />
57
57
  </Modal>
@@ -57,7 +57,7 @@ const meta = {
57
57
  },
58
58
  template: `
59
59
  <div class="max-w-sm">
60
- <Select v-model="value" :options="frameworks" v-bind="args" />
60
+ <Select v-bind="args" v-model="value" :options="frameworks" />
61
61
  <div class="mt-2 text-sm text-muted-foreground">Selected: {{ value ?? 'none' }}</div>
62
62
  </div>
63
63
  `,
@@ -27,7 +27,7 @@ const meta = {
27
27
  },
28
28
  template: `
29
29
  <div class="max-w-sm">
30
- <Slider v-model="value" v-bind="args" />
30
+ <Slider v-bind="args" v-model="value" />
31
31
  <div class="mt-2 text-sm text-muted-foreground">Value: {{ value }}</div>
32
32
  </div>
33
33
  `,
@@ -19,7 +19,7 @@ const meta = {
19
19
  },
20
20
  template: `
21
21
  <div class="flex items-center gap-4">
22
- <Switch v-model="on" v-bind="args" />
22
+ <Switch v-bind="args" v-model="on" />
23
23
  <div class="text-sm text-muted-foreground">Value: {{ on }}</div>
24
24
  </div>
25
25
  `,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polymarbot/nuxt-layer-shadcn-ui",
3
- "version": "0.5.4",
3
+ "version": "0.6.0",
4
4
  "description": "Nuxt layer providing shadcn-vue based UI components",
5
5
  "type": "module",
6
6
  "main": "./nuxt.config.ts",
@@ -42,5 +42,5 @@
42
42
  "vue-i18n": "^11",
43
43
  "vue-router": "^4 || ^5"
44
44
  },
45
- "gitHead": "fc48f5b21d76aa2ff0badd6ac6d9ccc5be906f26"
45
+ "gitHead": "750dccbf085f045771b445f9ac7fe0d722cd1a4c"
46
46
  }