@bagelink/vue 0.0.1262 → 0.0.1270

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 (51) hide show
  1. package/dist/components/AddressSearch.vue.d.ts +6 -0
  2. package/dist/components/AddressSearch.vue.d.ts.map +1 -1
  3. package/dist/components/DropDown.vue.d.ts +51 -48
  4. package/dist/components/DropDown.vue.d.ts.map +1 -1
  5. package/dist/components/Icon/Icon.vue.d.ts.map +1 -1
  6. package/dist/components/form/FieldArray.vue.d.ts.map +1 -1
  7. package/dist/components/form/inputs/DateInput.vue.d.ts +4 -1
  8. package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
  9. package/dist/components/form/inputs/PasswordInput.vue.d.ts.map +1 -1
  10. package/dist/components/form/inputs/RadioGroup.vue.d.ts +1 -1
  11. package/dist/components/form/inputs/RichText/composables/useCommands.d.ts.map +1 -1
  12. package/dist/components/form/inputs/RichText/composables/useEditor.d.ts +31 -23
  13. package/dist/components/form/inputs/RichText/composables/useEditor.d.ts.map +1 -1
  14. package/dist/components/form/inputs/RichText/composables/useEditorKeyboard.d.ts +2 -1
  15. package/dist/components/form/inputs/RichText/composables/useEditorKeyboard.d.ts.map +1 -1
  16. package/dist/components/form/inputs/RichText/config.d.ts +2 -1
  17. package/dist/components/form/inputs/RichText/config.d.ts.map +1 -1
  18. package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
  19. package/dist/components/form/inputs/RichText/utils/commands.d.ts +1 -0
  20. package/dist/components/form/inputs/RichText/utils/commands.d.ts.map +1 -1
  21. package/dist/components/form/inputs/RichText/utils/media.d.ts +5 -3
  22. package/dist/components/form/inputs/RichText/utils/media.d.ts.map +1 -1
  23. package/dist/components/form/inputs/RichText/utils/selection.d.ts.map +1 -1
  24. package/dist/components/form/inputs/SelectInput.vue.d.ts +12 -0
  25. package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
  26. package/dist/components/form/inputs/TelInput.vue.d.ts +8 -2
  27. package/dist/components/form/inputs/TelInput.vue.d.ts.map +1 -1
  28. package/dist/editor-7QC0nG_c.js +4 -0
  29. package/dist/editor-CpMNx6Eo.cjs +4 -0
  30. package/dist/index.cjs +1392 -820
  31. package/dist/index.mjs +1392 -820
  32. package/dist/style.css +100 -87
  33. package/package.json +1 -1
  34. package/src/components/DataTable/DataTable.vue +1 -1
  35. package/src/components/Dropdown.vue +5 -2
  36. package/src/components/Icon/Icon.vue +14 -0
  37. package/src/components/form/FieldArray.vue +3 -0
  38. package/src/components/form/inputs/DateInput.vue +341 -162
  39. package/src/components/form/inputs/PasswordInput.vue +5 -1
  40. package/src/components/form/inputs/RichText/components/EditorToolbar.vue +2 -2
  41. package/src/components/form/inputs/RichText/composables/useCommands.ts +53 -97
  42. package/src/components/form/inputs/RichText/composables/useEditor.ts +377 -270
  43. package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +124 -58
  44. package/src/components/form/inputs/RichText/config.ts +27 -3
  45. package/src/components/form/inputs/RichText/editor.css +29 -0
  46. package/src/components/form/inputs/RichText/index.vue +129 -55
  47. package/src/components/form/inputs/RichText/richTextTypes.d.ts +35 -49
  48. package/src/components/form/inputs/RichText/utils/commands.ts +181 -0
  49. package/src/components/form/inputs/RichText/utils/media.ts +64 -3
  50. package/src/components/form/inputs/RichText/utils/selection.ts +40 -5
  51. package/src/styles/text.css +0 -8
@@ -1,8 +1,13 @@
1
1
  <script setup lang="ts">
2
2
  import type { modeType } from '../../Calendar/typings/types'
3
3
  import { Btn, NumberInput, Dropdown, TextInput } from '@bagelink/vue'
4
+ import { computed, ref, onMounted, onBeforeUnmount } from 'vue'
4
5
  import Time, { WEEK_START_DAY } from '../../Calendar/helpers/Time'
5
6
 
7
+ // Types
8
+ type ViewMode = 'days' | 'months' | 'years'
9
+
10
+ // Props
6
11
  const props = withDefaults(
7
12
  defineProps<{
8
13
  required?: boolean
@@ -18,7 +23,6 @@ const props = withDefaults(
18
23
  firstDayOfWeek?: WEEK_START_DAY
19
24
  locale?: string
20
25
  center?: boolean
21
-
22
26
  }>(),
23
27
  {
24
28
  enableTime: false,
@@ -26,224 +30,395 @@ const props = withDefaults(
26
30
  small: false,
27
31
  timezone: 'UTC',
28
32
  mode: 'day',
29
- firstDayOfWeek: WEEK_START_DAY.MONDAY,
33
+ firstDayOfWeek: WEEK_START_DAY.SUNDAY,
30
34
  locale: ''
31
35
  },
32
36
  )
33
37
 
34
38
  const emit = defineEmits(['update:modelValue'])
35
- let isOpen = $ref(false)
36
- let currentMonth = $ref(new Date())
37
- type ViewMode = 'days' | 'months' | 'years'
38
- let currentView = $ref<ViewMode>('days')
39
39
 
40
+ // State
41
+ const isOpen = ref(false)
42
+ const currentMonth = ref(new Date())
43
+ const currentView = ref<ViewMode>('days')
44
+
45
+ // Time helper instance
40
46
  const time = new Time(props.firstDayOfWeek, props.locale)
41
47
 
42
- function formatDisplayDate(date: Date | string | undefined): string {
43
- if (!date) return ''
44
- const dateObj = typeof date === 'string' ? new Date(date) : date
48
+ // Date formatting composable
49
+ function useFormatting() {
50
+ const formatDisplayDate = (date: Date | string | undefined): string => {
51
+ if (!date) return ''
52
+ const dateObj = typeof date === 'string' ? new Date(date) : date
45
53
 
46
- if (props.enableTime) {
47
- return dateObj.toLocaleString(props.locale || undefined, {
54
+ const options: Intl.DateTimeFormatOptions = {
48
55
  year: 'numeric',
49
56
  month: 'short',
50
57
  day: 'numeric',
51
- hour: '2-digit',
52
- minute: '2-digit',
58
+ ...(props.enableTime && {
59
+ hour: '2-digit',
60
+ minute: '2-digit',
61
+ }),
53
62
  timeZone: props.timezone
54
- })
63
+ }
64
+
65
+ return dateObj.toLocaleString(props.locale || undefined, options)
55
66
  }
56
67
 
57
- return dateObj.toLocaleString(props.locale || undefined, {
58
- year: 'numeric',
59
- month: 'short',
60
- day: 'numeric',
61
- timeZone: props.timezone
62
- })
63
- }
68
+ const formatDate = (date: Date | string | undefined): string => {
69
+ if (!date) return ''
70
+ const dateObj = typeof date === 'string' ? new Date(date) : date
71
+ return props.enableTime
72
+ ? dateObj.toISOString().slice(0, 16)
73
+ : dateObj.toISOString().split('T')[0]
74
+ }
75
+
76
+ const parseUserInput = (input: string): Date | null => {
77
+ // Try parsing various date formats
78
+ const date = new Date(input)
79
+ if (!Number.isNaN(date.getTime())) {
80
+ return date
81
+ }
82
+
83
+ // Try DD/MM/YYYY format
84
+ const parts = input.split(/[/.-]/)
85
+ if (parts.length === 3) {
86
+ const [day, month, year] = parts.map(p => Number.parseInt(p, 10))
87
+ if (!Number.isNaN(day) && !Number.isNaN(month) && !Number.isNaN(year)) {
88
+ const date = new Date(year, month - 1, day)
89
+ if (date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day) {
90
+ return date
91
+ }
92
+ }
93
+ }
94
+
95
+ return null
96
+ }
64
97
 
65
- function formatDate(date: Date | string | undefined): string {
66
- if (!date) return ''
67
- const dateObj = typeof date === 'string' ? new Date(date) : date
68
- return props.enableTime ? dateObj.toISOString().slice(0, 16) : dateObj.toISOString().split('T')[0]
98
+ return {
99
+ formatDisplayDate,
100
+ formatDate,
101
+ parseUserInput
102
+ }
69
103
  }
70
104
 
71
- const formattedDisplayValue = $computed(() => formatDisplayDate(props.modelValue))
72
- const formattedMin = $computed(() => formatDate(props.min))
73
- const formattedMax = $computed(() => formatDate(props.max))
105
+ // Date validation composable
106
+ function useDateValidation() {
107
+ const isDateDisabled = (date: Date | null) => {
108
+ if (!date) return true
109
+ const minDate = props.min ? new Date(props.min) : null
110
+ const maxDate = props.max ? new Date(props.max) : null
74
111
 
75
- const selectedDate = $computed(() => {
76
- if (!props.modelValue) return null
77
- return typeof props.modelValue === 'string' ? new Date(props.modelValue) : props.modelValue
78
- })
112
+ if (minDate && date < minDate) return true
113
+ if (maxDate && date > maxDate) return true
114
+ return false
115
+ }
79
116
 
80
- const currentMonthDays = $computed(() => {
81
- const year = currentMonth.getFullYear()
82
- const month = currentMonth.getMonth()
83
- return time.getCalendarMonthSplitInWeeks(year, month).flat()
84
- })
117
+ const isYearDisabled = (year: number) => {
118
+ const minDate = props.min ? new Date(props.min) : null
119
+ const maxDate = props.max ? new Date(props.max) : null
85
120
 
86
- const currentMonthValue = $computed(() => ({
87
- month: currentMonth.getMonth(),
88
- year: currentMonth.getFullYear(),
89
- formatted: {
90
- month: time.getLocalizedNameOfMonth(currentMonth, 'long'),
91
- year: time.getLocalizedDateString(currentMonth).split('/').pop() // Get just the year part
121
+ if (minDate && year < minDate.getFullYear()) return true
122
+ if (maxDate && year > maxDate.getFullYear()) return true
123
+ return false
92
124
  }
93
- }))
94
125
 
95
- const months = $computed(() => Array.from({ length: 12 }, (_, i) => {
96
- const date = new Date(currentMonthValue.year, i, 1)
97
126
  return {
98
- name: time.getLocalizedNameOfMonth(date, 'short'),
99
- value: i,
100
- disabled: isDateDisabled(date)
127
+ isDateDisabled,
128
+ isYearDisabled
129
+ }
130
+ }
131
+
132
+ // Date state composable
133
+ function useDateState() {
134
+ const { formatDisplayDate, formatDate } = useFormatting()
135
+
136
+ const formattedDisplayValue = computed(() => formatDisplayDate(props.modelValue))
137
+ const formattedMin = computed(() => formatDate(props.min))
138
+ const formattedMax = computed(() => formatDate(props.max))
139
+ const selectedDate = computed(() => {
140
+ if (!props.modelValue) return null
141
+ return typeof props.modelValue === 'string' ? new Date(props.modelValue) : props.modelValue
142
+ })
143
+
144
+ return {
145
+ formattedDisplayValue,
146
+ formattedMin,
147
+ formattedMax,
148
+ selectedDate
101
149
  }
102
- }))
150
+ }
151
+
152
+ // Initialize core composables first
153
+ const { isDateDisabled, isYearDisabled } = useDateValidation()
154
+ const { formattedDisplayValue, formattedMin, formattedMax, selectedDate } = useDateState()
103
155
 
104
- const years = $computed(() => {
105
- const startYear = currentMonthValue.year - 10
106
- return Array.from({ length: 21 }, (_, i) => ({
107
- value: startYear + i,
108
- disabled: isYearDisabled(startYear + i)
156
+ // Calendar view composable
157
+ function useCalendarView() {
158
+ const currentMonthDays = computed(() => {
159
+ const year = currentMonth.value.getFullYear()
160
+ const month = currentMonth.value.getMonth()
161
+ return time.getCalendarMonthSplitInWeeks(year, month).flat()
162
+ })
163
+
164
+ const currentMonthValue = computed(() => ({
165
+ month: currentMonth.value.getMonth(),
166
+ year: currentMonth.value.getFullYear(),
167
+ formatted: {
168
+ month: time.getLocalizedNameOfMonth(currentMonth.value, 'long'),
169
+ year: time.getLocalizedDateString(currentMonth.value).split('/').pop()
170
+ }
109
171
  }))
110
- })
111
172
 
112
- const weekDays = $computed(() => {
113
- const weekStart = new Date()
114
- weekStart.setDate(weekStart.getDate() - weekStart.getDay() + (props.firstDayOfWeek === WEEK_START_DAY.MONDAY ? 1 : 0))
115
- return Array.from({ length: 7 }, (_, i) => {
116
- const day = new Date(weekStart)
117
- day.setDate(weekStart.getDate() + i)
118
- return time.getLocalizedNameOfWeekday(day, 'short')
173
+ const months = computed(() => Array.from({ length: 12 }, (_, i) => {
174
+ const date = new Date(currentMonthValue.value.year, i, 1)
175
+ return {
176
+ name: time.getLocalizedNameOfMonth(date, 'short'),
177
+ value: i,
178
+ disabled: isDateDisabled(date)
179
+ }
180
+ }))
181
+
182
+ const years = computed(() => {
183
+ const startYear = currentMonthValue.value.year - 10
184
+ return Array.from({ length: 21 }, (_, i) => ({
185
+ value: startYear + i,
186
+ disabled: isYearDisabled(startYear + i)
187
+ }))
119
188
  })
120
- })
121
189
 
122
- function isDateDisabled(date: Date | null) {
123
- if (!date) return true
124
- const minDate = props.min ? new Date(props.min) : null
125
- const maxDate = props.max ? new Date(props.max) : null
190
+ const weekDays = computed(() => {
191
+ const weekStart = new Date()
192
+ weekStart.setDate(weekStart.getDate() - weekStart.getDay()
193
+ + (props.firstDayOfWeek === WEEK_START_DAY.MONDAY ? 1 : 0))
194
+ return Array.from({ length: 7 }, (_, i) => {
195
+ const day = new Date(weekStart)
196
+ day.setDate(weekStart.getDate() + i)
197
+ return time.getLocalizedNameOfWeekday(day, 'short')
198
+ })
199
+ })
126
200
 
127
- if (minDate && date < minDate) return true
128
- if (maxDate && date > maxDate) return true
129
- return false
130
- }
201
+ const isSelected = (date: Date | null) => {
202
+ if (!date || !selectedDate.value) return false
203
+ return date.getFullYear() === selectedDate.value.getFullYear()
204
+ && date.getMonth() === selectedDate.value.getMonth()
205
+ && date.getDate() === selectedDate.value.getDate()
206
+ }
131
207
 
132
- function isYearDisabled(year: number) {
133
- const minDate = props.min ? new Date(props.min) : null
134
- const maxDate = props.max ? new Date(props.max) : null
208
+ const isToday = (date: Date | null) => {
209
+ if (!date) return false
210
+ return time.dateIsToday(date)
211
+ }
135
212
 
136
- if (minDate && year < minDate.getFullYear()) return true
137
- if (maxDate && year > maxDate.getFullYear()) return true
138
- return false
139
- }
213
+ const isNotInMonth = (date: Date) => {
214
+ return time.isTrailingOrLeadingDate(date, currentMonth.value.getMonth())
215
+ }
140
216
 
141
- function selectMonth(monthIndex: number) {
142
- currentMonth = new Date(currentMonth.getFullYear(), monthIndex, 1)
143
- currentView = 'days'
217
+ return {
218
+ currentMonthDays,
219
+ currentMonthValue,
220
+ months,
221
+ years,
222
+ weekDays,
223
+ isSelected,
224
+ isToday,
225
+ isNotInMonth
226
+ }
144
227
  }
145
228
 
146
- function selectYear(year: number) {
147
- currentMonth = new Date(year, currentMonth.getMonth(), 1)
148
- currentView = 'months'
149
- }
229
+ // Navigation handlers
230
+ function useNavigation() {
231
+ const selectMonth = (monthIndex: number) => {
232
+ currentMonth.value = new Date(currentMonth.value.getFullYear(), monthIndex, 1)
233
+ currentView.value = 'days'
234
+ }
150
235
 
151
- function previousMonth() {
152
- currentMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1)
153
- }
236
+ const selectYear = (year: number) => {
237
+ currentMonth.value = new Date(year, currentMonth.value.getMonth(), 1)
238
+ currentView.value = 'months'
239
+ }
240
+
241
+ const previousMonth = () => {
242
+ currentMonth.value = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() - 1, 1)
243
+ }
154
244
 
155
- function nextMonth() {
156
- currentMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1)
245
+ const nextMonth = () => {
246
+ currentMonth.value = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() + 1, 1)
247
+ }
248
+
249
+ const previousYear = () => {
250
+ const offset = currentView.value === 'months' ? 1 : 21
251
+ currentMonth.value = new Date(currentMonth.value.getFullYear() - offset, currentMonth.value.getMonth(), 1)
252
+ }
253
+
254
+ const nextYear = () => {
255
+ const offset = currentView.value === 'months' ? 1 : 21
256
+ currentMonth.value = new Date(currentMonth.value.getFullYear() + offset, currentMonth.value.getMonth(), 1)
257
+ }
258
+
259
+ return {
260
+ selectMonth,
261
+ selectYear,
262
+ previousMonth,
263
+ nextMonth,
264
+ previousYear,
265
+ nextYear
266
+ }
157
267
  }
158
268
 
159
- function previousYear() {
160
- const offset = currentView === 'months' ? 1 : 21
161
- currentMonth = new Date(currentMonth.getFullYear() - offset, currentMonth.getMonth(), 1)
269
+ // Time handling composable
270
+ function useTimeHandling() {
271
+ const hours = computed(() => selectedDate.value?.getHours() ?? 0)
272
+ const minutes = computed(() => selectedDate.value?.getMinutes() ?? 0)
273
+
274
+ const handleHourInput = (value: number) => {
275
+ if (!selectedDate.value) return
276
+ const newDate = new Date(selectedDate.value)
277
+ newDate.setHours(value)
278
+ emit('update:modelValue', newDate.toISOString())
279
+ }
280
+
281
+ const handleMinuteInput = (value: number) => {
282
+ if (!selectedDate.value) return
283
+ const newDate = new Date(selectedDate.value)
284
+ newDate.setMinutes(value)
285
+ emit('update:modelValue', newDate.toISOString())
286
+ }
287
+
288
+ const timezoneDisplay = computed(() => {
289
+ if (!props.enableTime) return ''
290
+ try {
291
+ return new Date().toLocaleString('en-US', {
292
+ timeZoneName: 'short',
293
+ timeZone: props.timezone
294
+ }).split(' ').pop()
295
+ } catch {
296
+ return 'UTC'
297
+ }
298
+ })
299
+
300
+ return {
301
+ hours,
302
+ minutes,
303
+ handleHourInput,
304
+ handleMinuteInput,
305
+ timezoneDisplay
306
+ }
162
307
  }
163
308
 
164
- function nextYear() {
165
- const offset = currentView === 'months' ? 1 : 21
166
- currentMonth = new Date(currentMonth.getFullYear() + offset, currentMonth.getMonth(), 1)
309
+ // Input handling composable
310
+ function useInputHandling() {
311
+ const { parseUserInput } = useFormatting()
312
+ const inputValue = ref('')
313
+
314
+ const handleInput = (event: Event) => {
315
+ const input = event.target as HTMLInputElement
316
+ inputValue.value = input.value
317
+
318
+ const date = parseUserInput(input.value)
319
+ if (date) {
320
+ if (props.enableTime) {
321
+ emit('update:modelValue', date.toISOString())
322
+ } else {
323
+ const utcDate = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()))
324
+ emit('update:modelValue', utcDate.toISOString().split('T')[0])
325
+ }
326
+ }
327
+ }
328
+
329
+ const handleFocus = (e: FocusEvent) => {
330
+ e.preventDefault()
331
+ e.stopPropagation()
332
+ isOpen.value = true
333
+ }
334
+
335
+ const handleClick = (e: MouseEvent) => {
336
+ e.preventDefault()
337
+ e.stopPropagation()
338
+ }
339
+
340
+ const handleKeydown = (event: KeyboardEvent) => {
341
+ if (event.key === 'Escape') {
342
+ isOpen.value = false
343
+ } else if (event.key === 'Enter' && inputValue.value) {
344
+ const date = parseUserInput(inputValue.value)
345
+ if (date) {
346
+ if (props.enableTime) {
347
+ emit('update:modelValue', date.toISOString())
348
+ } else {
349
+ const utcDate = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()))
350
+ emit('update:modelValue', utcDate.toISOString().split('T')[0])
351
+ }
352
+ isOpen.value = false
353
+ }
354
+ }
355
+ }
356
+
357
+ return {
358
+ inputValue,
359
+ handleInput,
360
+ handleFocus,
361
+ handleClick,
362
+ handleKeydown
363
+ }
167
364
  }
168
365
 
366
+ // Initialize input handling
367
+ const { inputValue, handleInput, handleFocus, handleClick, handleKeydown } = useInputHandling()
368
+
369
+ // Initialize remaining composables
370
+ const { currentMonthDays, currentMonthValue, months, years, weekDays, isSelected, isToday, isNotInMonth } = useCalendarView()
371
+ const { selectMonth, selectYear, previousMonth, nextMonth, previousYear, nextYear } = useNavigation()
372
+ const { hours, minutes, handleHourInput, handleMinuteInput, timezoneDisplay } = useTimeHandling()
373
+
374
+ // Date selection handler
169
375
  function selectDate(date: Date | null) {
170
376
  if (!date || !props.editMode) return
171
377
 
172
- // Create date at start of day in the target timezone
378
+ // Create date in the target timezone
379
+ const tzOffset = new Date().getTimezoneOffset()
173
380
  const newDate = new Date(date.getFullYear(), date.getMonth(), date.getDate())
174
381
 
175
- // If time is enabled, preserve existing time or set to current time
176
382
  if (props.enableTime) {
177
- const currentHours = selectedDate?.getHours() ?? new Date().getHours()
178
- const currentMinutes = selectedDate?.getMinutes() ?? new Date().getMinutes()
383
+ const currentHours = selectedDate.value?.getHours() ?? new Date().getHours()
384
+ const currentMinutes = selectedDate.value?.getMinutes() ?? new Date().getMinutes()
179
385
  newDate.setHours(currentHours)
180
386
  newDate.setMinutes(currentMinutes)
387
+
388
+ // Adjust for timezone when time is enabled
389
+ if (props.timezone === 'UTC') {
390
+ newDate.setMinutes(newDate.getMinutes() + tzOffset)
391
+ }
181
392
  emit('update:modelValue', newDate.toISOString())
182
393
  } else {
183
- // For dates without time, ensure time is set to midnight UTC
184
- newDate.setUTCHours(0, 0, 0, 0)
185
- emit('update:modelValue', newDate.toISOString().split('T')[0])
186
- isOpen = false
187
- }
188
- }
189
-
190
- function handleInput(event: Event) {
191
- const input = event.target as HTMLInputElement
192
- if (!input.value) {
193
- emit('update:modelValue', '')
194
- return
394
+ // For date-only selection, ensure we're working with UTC midnight
395
+ const utcDate = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()))
396
+ emit('update:modelValue', utcDate.toISOString().split('T')[0])
397
+ isOpen.value = false
195
398
  }
196
-
197
- const date = new Date(input.value)
198
- emit('update:modelValue', props.enableTime ? date.toISOString() : date.toISOString().split('T')[0])
199
399
  }
200
400
 
201
- const hours = $computed(() => selectedDate?.getHours() ?? 0)
202
- const minutes = $computed(() => selectedDate?.getMinutes() ?? 0)
401
+ const datePickerRef = ref<HTMLElement | null>(null)
402
+ const calendarRef = ref<HTMLElement | null>(null)
203
403
 
204
- function handleHourInput(value: number) {
205
- if (!selectedDate) return
206
- const newDate = new Date(selectedDate)
207
- newDate.setHours(value)
208
- emit('update:modelValue', newDate.toISOString())
209
- }
210
-
211
- function handleMinuteInput(value: number) {
212
- if (!selectedDate) return
213
- const newDate = new Date(selectedDate)
214
- newDate.setMinutes(value)
215
- emit('update:modelValue', newDate.toISOString())
216
- }
217
-
218
- function isSelected(date: Date | null) {
219
- if (!date || !selectedDate) return false
220
- return date.toISOString().split('T')[0] === selectedDate.toISOString().split('T')[0]
221
- }
404
+ onMounted(() => {
405
+ const handleDocumentClick = (e: MouseEvent) => {
406
+ const target = e.target as HTMLElement
407
+ if (!datePickerRef.value?.contains(target) && !calendarRef.value?.contains(target)) {
408
+ isOpen.value = false
409
+ }
410
+ }
222
411
 
223
- function isToday(date: Date | null) {
224
- if (!date) return false
225
- return time.dateIsToday(date)
226
- }
412
+ document.addEventListener('click', handleDocumentClick)
227
413
 
228
- const timezoneDisplay = $computed(() => {
229
- if (!props.enableTime) return ''
230
- try {
231
- return new Date().toLocaleString('en-US', {
232
- timeZoneName: 'short',
233
- timeZone: props.timezone
234
- }).split(' ').pop()
235
- } catch {
236
- return 'UTC'
237
- }
414
+ onBeforeUnmount(() => {
415
+ document.removeEventListener('click', handleDocumentClick)
416
+ })
238
417
  })
239
-
240
- function isNotInMonth(date: Date) {
241
- return time.isTrailingOrLeadingDate(date, currentMonth.getMonth())
242
- }
243
418
  </script>
244
419
 
245
420
  <template>
246
- <div class="bagel-input" :class="{ small }" :title="label">
421
+ <div class="bagel-input" :class="{ small }" :title="label" @focusin="handleFocus">
247
422
  <label v-if="label">
248
423
  {{ label }}
249
424
  <span v-if="required" class="required">*</span>
@@ -252,11 +427,11 @@ function isNotInMonth(date: Date) {
252
427
  <Dropdown
253
428
  :shown="isOpen"
254
429
  placement="bottom-start"
255
- @apply-show="isOpen = true"
256
- @apply-hide="isOpen = false"
430
+ :autoHide="false"
431
+ :triggers="['click']"
257
432
  >
258
433
  <template #trigger>
259
- <div class="date-picker-container">
434
+ <div ref="datePickerRef" class="date-picker-container" @mousedown.stop @click.stop>
260
435
  <TextInput
261
436
  :modelValue="formattedDisplayValue"
262
437
  icon="calendar"
@@ -266,14 +441,18 @@ function isNotInMonth(date: Date) {
266
441
  :disabled="!editMode"
267
442
  class="date-input"
268
443
  :class="{
269
- 'txt-center': center }"
270
- readonly
271
- @click="isOpen = true"
444
+ 'txt-center': center,
445
+ }"
446
+ :readonly="false"
447
+ @input="handleInput"
448
+ @focus="handleFocus"
449
+ @click="handleClick"
450
+ @keydown="handleKeydown"
272
451
  />
273
452
  </div>
274
453
  </template>
275
454
 
276
- <div class="flex gap-075 p-05 m_flex-wrap calendar-container justify-content-center h-100p">
455
+ <div ref="calendarRef" class="ltr flex gap-075 p-05 m_flex-wrap calendar-container justify-content-center h-100p" @click.stop>
277
456
  <div class="calendar-section m_border-none pe-05 m_p-0">
278
457
  <div class="flex space-between pb-1">
279
458
  <template v-if="currentView === 'days'">
@@ -43,7 +43,7 @@ const inputType = $computed(() => (showPwd.value ? 'text' : 'password'))
43
43
  </script>
44
44
 
45
45
  <template>
46
- <div class="relative">
46
+ <div class="relative passwordInput">
47
47
  <TextInput
48
48
  v-model="password"
49
49
  v-bind="props"
@@ -66,4 +66,8 @@ const inputType = $computed(() => (showPwd.value ? 'text' : 'password'))
66
66
  .m-password {
67
67
  height: var(--input-height) !important;
68
68
  }
69
+ [dir='rtl'] .passwordInput input {
70
+ direction: ltr;
71
+ text-align: right;
72
+ }
69
73
  </style>
@@ -1,10 +1,10 @@
1
1
  <script lang="ts" setup>
2
2
  import type { ToolbarConfig, ToolbarConfigOption, ToolbarOption } from '../richTextTypes'
3
3
  import { Btn, Dropdown } from '@bagelink/vue'
4
- import { defaultToolbarConfig, toolbarOptions } from '../config'
4
+ import { basicToolbarConfig, toolbarOptions } from '../config'
5
5
  import GridBox from './gridBox.vue'
6
6
 
7
- const { config = defaultToolbarConfig, selectedStyles } = defineProps<{
7
+ const { config = basicToolbarConfig, selectedStyles } = defineProps<{
8
8
  config?: ToolbarConfig
9
9
  selectedStyles: Set<string>
10
10
  }>()