@bagelink/vue 1.2.33 → 1.2.41

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 (46) hide show
  1. package/dist/components/calendar/CalendarPopover.vue.d.ts +179 -0
  2. package/dist/components/calendar/CalendarPopover.vue.d.ts.map +1 -0
  3. package/dist/components/calendar/CalendarTypes.d.ts +15 -0
  4. package/dist/components/calendar/CalendarTypes.d.ts.map +1 -1
  5. package/dist/components/calendar/Index.vue.d.ts +21 -12
  6. package/dist/components/calendar/Index.vue.d.ts.map +1 -1
  7. package/dist/components/calendar/views/AgendaView.vue.d.ts +8 -0
  8. package/dist/components/calendar/views/AgendaView.vue.d.ts.map +1 -1
  9. package/dist/components/calendar/views/CalendarPopover.vue.d.ts +175 -0
  10. package/dist/components/calendar/views/CalendarPopover.vue.d.ts.map +1 -0
  11. package/dist/components/calendar/views/DayView.vue.d.ts +10 -32
  12. package/dist/components/calendar/views/DayView.vue.d.ts.map +1 -1
  13. package/dist/components/calendar/views/MonthView.vue.d.ts +10 -170
  14. package/dist/components/calendar/views/MonthView.vue.d.ts.map +1 -1
  15. package/dist/components/calendar/views/WeekView.vue.d.ts +12 -168
  16. package/dist/components/calendar/views/WeekView.vue.d.ts.map +1 -1
  17. package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
  18. package/dist/components/form/inputs/DatePicker.vue.d.ts.map +1 -1
  19. package/dist/composables/useDevice.d.ts +3 -0
  20. package/dist/composables/useDevice.d.ts.map +1 -1
  21. package/dist/index.cjs +446 -309
  22. package/dist/index.mjs +446 -309
  23. package/dist/style.css +231 -179
  24. package/dist/types/BagelForm.d.ts +14 -11
  25. package/dist/types/BagelForm.d.ts.map +1 -1
  26. package/dist/utils/BagelFormUtils.d.ts +10 -10
  27. package/dist/utils/BagelFormUtils.d.ts.map +1 -1
  28. package/dist/utils/calendar/dateUtils.d.ts +10 -10
  29. package/dist/utils/calendar/dateUtils.d.ts.map +1 -1
  30. package/package.json +1 -1
  31. package/src/components/calendar/CalendarPopover.vue +102 -0
  32. package/src/components/calendar/CalendarTypes.ts +14 -0
  33. package/src/components/calendar/Index.vue +77 -35
  34. package/src/components/calendar/views/AgendaView.vue +26 -2
  35. package/src/components/calendar/views/DayView.vue +83 -104
  36. package/src/components/calendar/views/MonthView.vue +39 -67
  37. package/src/components/calendar/views/WeekView.vue +229 -136
  38. package/src/components/form/inputs/DateInput.vue +14 -3
  39. package/src/components/form/inputs/DatePicker.vue +7 -0
  40. package/src/composables/useDevice.ts +13 -2
  41. package/src/styles/layout.css +14 -0
  42. package/src/styles/mobilLayout.css +12 -0
  43. package/src/types/BagelForm.ts +30 -53
  44. package/src/utils/BagelFormUtils.ts +11 -10
  45. package/src/utils/calendar/dateUtils.ts +42 -45
  46. package/src/components/calendar/utils.ts +0 -70
@@ -277,6 +277,18 @@
277
277
  min-height: 100%;
278
278
  }
279
279
 
280
+ .m_h-min-unset,
281
+ .m_min-h-unset {
282
+ min-height: 100%;
283
+ }
284
+
285
+ .m_vh-min-100,
286
+ .m_min100vh,
287
+ .m_min-100vh,
288
+ .m_h-min100vh {
289
+ min-height: 100vh !important;
290
+ }
291
+
280
292
  .m_min-0,
281
293
  .m_min0,
282
294
  .m_wmin0p,
@@ -1,4 +1,7 @@
1
1
  import type { SelectInput, TextInput } from '@bagelink/vue'
2
+ import type { Paths, Get, IterableElement } from 'type-fest'
3
+ import type { ToString } from 'type-fest/source/internal'
4
+ import type { LiteralStringUnion } from 'type-fest/source/literal-union'
2
5
  import type { VNode } from 'vue'
3
6
  import type { ComponentExposed } from 'vue-component-type-helpers'
4
7
 
@@ -25,68 +28,42 @@ export type BagelFieldOptions<T> = (
25
28
  | ((val: any, rowData?: T) => void)
26
29
  )
27
30
 
28
- export type GenericAssertFn<T> = (val: any, row?: T) => boolean
29
-
30
- export type TypedAssertFn<T, K> = (
31
- K extends keyof T ?
32
- (val?: FieldVal<T, K>, row?: T) => boolean :
33
- GenericAssertFn<T>
31
+ export type VIfType<T, P extends Path<T>> = (
32
+ string |
33
+ boolean |
34
+ ((val?: FieldVal<T, P>, rowData?: T) => boolean)
34
35
  )
35
36
 
36
- // export type VIfType<T, K> = string | boolean | TypedAssertFn<T, K>
37
-
38
- export type VIfType<T, P> = string | boolean | ((val?: FieldVal<T, P>, rowData?: T) => boolean)
39
-
40
- export type ValidationFn<T, K> = (
41
- val: FieldVal<T, K>,
37
+ export type ValidationFn<T, P extends Path<T>> = (
38
+ val: FieldVal<T, P>,
42
39
  rowData?: T,
43
40
  ) => string | undefined
44
41
 
45
- export type NonArrayMethodKeys<T> = Exclude<
46
- keyof T,
47
- // filter out function-like or symbol-based keys from arrays
48
- keyof any[] | symbol
49
- >
50
-
51
- export type Path<T> = {
52
- [K in NonArrayMethodKeys<T> & (string | number)]:
53
- T[K] extends object ?
54
- (
55
- | `${K}`
56
- | (
57
- Path<T[K]> extends infer Rest ?
58
- Rest extends string | number ?
59
- `${K}.${Rest}` :
60
- never :
61
- never
62
- )
63
- ) :
64
- `${K}`
65
- }[NonArrayMethodKeys<T> & (string | number)]
66
-
67
- export type FieldVal<T, P> =
68
- P extends `${infer Key}.${infer Rest}` ?
69
- Key extends keyof T ?
70
- FieldVal<T[Key], Rest> :
71
- never :
72
- P extends keyof T ?
73
- T[P] : never
74
-
75
- export type ArrayFieldVal<
76
- T,
77
- P,
78
- FV = FieldVal<T, P>
79
- > = (
80
- FV extends Array<infer U> ?
81
- U :
82
- FV extends object ?
83
- FV :
84
- never
42
+ export type _Path<T> = (
43
+ ToString<
44
+ Paths<
45
+ T,
46
+ {
47
+ bracketNotation: false
48
+ }
49
+ >
50
+ >
85
51
  )
52
+ export type Path<T> = (
53
+ FieldVal<T, _Path<T>> extends Array<any> ?
54
+ LiteralStringUnion<_Path<T>> :
55
+ _Path<T>
56
+ )
57
+
58
+ /** The value type at path P in object T. */
59
+ export type FieldVal<T, P extends Path<T>> = Get<T, P>
60
+
61
+ /** If path P in T is an array, this gives the array's element type. */
62
+ export type ArrayFieldVal<T, P extends Path<T>> = IterableElement<Get<T, P>>
86
63
 
87
64
  export type SchemaChildrenT<T> = (Field<T> | string | VNode)[]
88
65
 
89
- export interface BaseBagelField<T, P> {
66
+ export interface BaseBagelField<T, P extends Path<T>> {
90
67
  '$el'?: any
91
68
  'id'?: P
92
69
  'label'?: string
@@ -1,7 +1,7 @@
1
1
  import type { ArrayFieldVal, Attributes, BaseBagelField, BglFormSchemaT, Field, IconType, InputBagelField, Option, Path, SchemaChildrenT, SelectBagelField, VIfType } from '@bagelink/vue'
2
2
  import type { UploadInputProps } from '../components/form/inputs/Upload/upload.types'
3
3
 
4
- interface InputOptions<T, K> {
4
+ interface InputOptions<T, K extends Path<T>> {
5
5
  required?: boolean
6
6
  placeholder?: string
7
7
  class?: string
@@ -12,14 +12,14 @@ interface InputOptions<T, K> {
12
12
  vIf?: VIfType<T, K>
13
13
  }
14
14
 
15
- interface DateOptions<T, K> extends InputOptions<T, K> {
15
+ interface DateOptions<T, K extends Path<T>> extends InputOptions<T, K> {
16
16
  enableTime?: boolean
17
17
  mode?: 'day' | 'month' | 'year'
18
18
  locale?: string
19
19
  timezone?: string
20
20
  }
21
21
 
22
- interface TextInputOptions<T, K> extends InputOptions<T, K> {
22
+ interface TextInputOptions<T, K extends Path<T>> extends InputOptions<T, K> {
23
23
  type?: 'text' | 'tel' | 'email' | 'time'
24
24
  pattern?: string
25
25
  multiline?: boolean
@@ -30,14 +30,14 @@ interface TextInputOptions<T, K> extends InputOptions<T, K> {
30
30
  iconStart?: IconType
31
31
  }
32
32
 
33
- interface SlctInputOptions<T, K> extends InputOptions<T, K> {
33
+ interface SlctInputOptions<T, K extends Path<T>> extends InputOptions<T, K> {
34
34
  searchable?: boolean
35
35
  multiselect?: boolean
36
36
  clearable?: boolean
37
37
  onSearch?: (search: string) => any
38
38
  }
39
39
 
40
- interface NumFieldOptions<T, K> extends InputOptions<T, K> {
40
+ interface NumFieldOptions<T, K extends Path<T>> extends InputOptions<T, K> {
41
41
  max?: number
42
42
  min?: number
43
43
  step?: number
@@ -47,7 +47,7 @@ interface NumFieldOptions<T, K> extends InputOptions<T, K> {
47
47
  useGrouping?: boolean
48
48
  }
49
49
 
50
- type RichTextOptions<T, K> = InputOptions<T, K>
50
+ type RichTextOptions<T, K extends Path<T>> = InputOptions<T, K>
51
51
 
52
52
  export function getBaseField<T, P extends Path<T>>(
53
53
  id?: P,
@@ -137,7 +137,7 @@ export function selectField<T, P extends Path<T>>(
137
137
 
138
138
  export const slctField = selectField
139
139
 
140
- interface CheckInputOptions<T, K> extends InputOptions<T, K> {
140
+ interface CheckInputOptions<T, K extends Path<T>> extends InputOptions<T, K> {
141
141
  value?: string
142
142
  }
143
143
 
@@ -212,6 +212,7 @@ export function numField<T, P extends Path<T>>(
212
212
  }
213
213
  }
214
214
 
215
+ // export function frmRow<T, P extends Path<T>>(...children: SchemaChildrenT<T>): BaseBagelField<T, P> {
215
216
  export function frmRow<T>(...children: SchemaChildrenT<T>): Field<T> {
216
217
  return {
217
218
  $el: 'div',
@@ -220,7 +221,7 @@ export function frmRow<T>(...children: SchemaChildrenT<T>): Field<T> {
220
221
  }
221
222
  }
222
223
 
223
- export type UploadOptions<T, K> = InputOptions<T, K> & UploadInputProps
224
+ export type UploadOptions<T, K extends Path<T>> = InputOptions<T, K> & UploadInputProps
224
225
 
225
226
  export function uploadField<T, P extends Path<T>>(id: P, label?: string, options?: UploadOptions<T, P>): BaseBagelField<T, P> {
226
227
  return {
@@ -234,7 +235,7 @@ export function uploadField<T, P extends Path<T>>(id: P, label?: string, options
234
235
  }
235
236
  }
236
237
 
237
- interface RangeOptions<T, K> extends InputOptions<T, K> {
238
+ interface RangeOptions<T, K extends Path<T>> extends InputOptions<T, K> {
238
239
  min?: number
239
240
  max?: number
240
241
  step?: number
@@ -327,7 +328,7 @@ export function findBglFieldById<T>(id: string, _schema: BglFormSchemaT<T>): Fie
327
328
  return undefined
328
329
  }
329
330
 
330
- export interface ArrayFieldOptions<T, K> extends InputOptions<T, K> {
331
+ export interface ArrayFieldOptions<T, K extends Path<T>> extends InputOptions<T, K> {
331
332
  delete?: boolean
332
333
  add?: boolean
333
334
  }
@@ -2,38 +2,38 @@ import type { DateLike } from '@vueuse/core'
2
2
  import type { AvailableTimeLanguages, DateTimeAcceptedFormats, LanguageTranslations, TimeUnit } from '../../types/timeAgoT'
3
3
 
4
4
  interface TimeDeltaOptions {
5
- day?: number
6
- hour?: number
7
- minute?: number
8
- second?: number
9
- week?: number
10
- month?: number
11
- year?: number
5
+ Day?: number
6
+ Hour?: number
7
+ Minute?: number
8
+ Second?: number
9
+ Week?: number
10
+ Month?: number
11
+ Year?: number
12
12
  }
13
13
 
14
14
  export function timeDelta(date: string | Date, options: TimeDeltaOptions) {
15
15
  date = new Date(date)
16
- const { day, hour, minute, second, week, month, year } = options
17
- if (day) {
18
- date.setDate(date.getDate() + day)
16
+ const { Day, Hour, Minute, Second, Week, Month, Year } = options
17
+ if (Day) {
18
+ date.setDate(date.getDate() + Day)
19
19
  }
20
- if (hour) {
21
- date.setHours(date.getHours() + hour)
20
+ if (Hour) {
21
+ date.setHours(date.getHours() + Hour)
22
22
  }
23
- if (minute) {
24
- date.setMinutes(date.getMinutes() + minute)
23
+ if (Minute) {
24
+ date.setMinutes(date.getMinutes() + Minute)
25
25
  }
26
- if (second) {
27
- date.setSeconds(date.getSeconds() + second)
26
+ if (Second) {
27
+ date.setSeconds(date.getSeconds() + Second)
28
28
  }
29
- if (week) {
30
- date.setDate(date.getDate() + week * 7)
29
+ if (Week) {
30
+ date.setDate(date.getDate() + Week * 7)
31
31
  }
32
- if (month) {
33
- date.setMonth(date.getMonth() + month)
32
+ if (Month) {
33
+ date.setMonth(date.getMonth() + Month)
34
34
  }
35
- if (year) {
36
- date.setFullYear(date.getFullYear() + year)
35
+ if (Year) {
36
+ date.setFullYear(date.getFullYear() + Year)
37
37
  }
38
38
  return date
39
39
  }
@@ -158,9 +158,9 @@ function getBrowserNavigatorLocale(): string {
158
158
  * @param timeZone The timezone to use (e.g., 'UTC', 'America/New_York')
159
159
  * @returns Date parts with timezone adjustment applied
160
160
  */
161
- export function handleTimezone(date: Date, timeZone: string): Date {
161
+ export function handleTimezone(date: Date, locale: Intl.LocalesArgument, intFmtOpt: Intl.DateTimeFormatOptions): Date {
162
162
  // If timeZone is UTC, convert to UTC directly
163
- if (timeZone === 'UTC') {
163
+ if (intFmtOpt.timeZone === 'UTC') {
164
164
  const utcDate = new Date(date.getTime())
165
165
  utcDate.setMinutes(utcDate.getMinutes() + date.getTimezoneOffset())
166
166
  return utcDate
@@ -169,16 +169,7 @@ export function handleTimezone(date: Date, timeZone: string): Date {
169
169
  // For other timezones, use the Intl API
170
170
  try {
171
171
  // Get the target timezone's offset at this specific date
172
- const formatter = new Intl.DateTimeFormat('en-US', {
173
- timeZone,
174
- timeZoneName: 'short',
175
- year: 'numeric',
176
- month: 'numeric',
177
- day: 'numeric',
178
- hour: 'numeric',
179
- minute: 'numeric',
180
- second: 'numeric',
181
- })
172
+ const formatter = new Intl.DateTimeFormat(locale, intFmtOpt)
182
173
 
183
174
  // Format the date in the target timezone
184
175
  const formattedParts = formatter.formatToParts(date)
@@ -203,14 +194,15 @@ export function handleTimezone(date: Date, timeZone: string): Date {
203
194
 
204
195
  return adjustedDate
205
196
  } catch (error) {
206
- console.warn(`Error handling timezone ${timeZone}:`, error)
197
+ console.warn(`Error handling timezone ${intFmtOpt.timeZone}:`, error)
207
198
  return date // Return original date on error
208
199
  }
209
200
  }
210
201
 
211
- export function getDatePartsMap(date: Date, locale: Intl.LocalesArgument, timeZone?: string) {
202
+ export function getDatePartsMap(date: Date, locale: Intl.LocalesArgument, intFmtOpt?: Intl.DateTimeFormatOptions) {
212
203
  // Apply timezone adjustment if specified
213
- const d = timeZone ? handleTimezone(date, timeZone) : date
204
+ const d = intFmtOpt?.timeZone ? handleTimezone(date, locale, intFmtOpt) : date
205
+ // const d = date
214
206
 
215
207
  /// keep-sorted
216
208
  return {
@@ -242,7 +234,7 @@ const _orderedDateTokens = (
242
234
  // ? no longer creating the Regex Objs it in a loop
243
235
  const _tokenRegExPattern = new RegExp(_orderedDateTokens.map(token => token).join('|'), 'g')
244
236
 
245
- export interface FormatDateOptions {
237
+ export interface FormatDateOptions extends Partial<Pick<Intl.DateTimeFormatOptions, 'hour12'>> {
246
238
  fmt?: DateTimeAcceptedFormats
247
239
  locale?: Intl.LocalesArgument
248
240
  tz?: string
@@ -258,9 +250,9 @@ export interface FormatDateOptions {
258
250
  */
259
251
  export function formatDate(
260
252
  date?: DateLike,
261
- opts: FormatDateOptions = {}
253
+ opts: FormatDateOptions = {},
262
254
  ): string {
263
- let { fmt: format, locale, tz: timeZone } = opts
255
+ let { fmt: format, locale, tz: timeZone, ...rest } = opts
264
256
 
265
257
  if (!date) return ''
266
258
  format = format || 'DD.MM.YY'
@@ -276,21 +268,26 @@ export function formatDate(
276
268
  return ''
277
269
  }
278
270
 
279
- const datePartsMap = getDatePartsMap(d, locale, timeZone)
280
-
281
271
  // For more complex formats that need localization, use Intl.DateTimeFormat
282
272
  /// keep-sorted
283
- const formatter = new Intl.DateTimeFormat(locale, {
273
+ const intFmtOpt: Intl.DateTimeFormatOptions = {
284
274
  day: 'numeric',
285
275
  hour: '2-digit',
286
- hour12: true,
276
+
277
+ // Set default hour12 to true if not explicitly set
278
+ // hour12: true,
279
+ hour12: rest.hour12 === undefined ? true : rest.hour12,
287
280
  minute: '2-digit',
288
281
  month: 'long',
289
282
  second: '2-digit',
290
283
  timeZone, // Add timeZone if provided
291
284
  weekday: 'long',
292
285
  year: 'numeric',
293
- })
286
+ }
287
+
288
+ const datePartsMap = getDatePartsMap(d, locale, intFmtOpt)
289
+
290
+ const formatter = new Intl.DateTimeFormat(locale, intFmtOpt)
294
291
 
295
292
  const formattedParts = formatter.formatToParts(d)
296
293
  const partsMap: Partial<Record<Intl.DateTimeFormatPartTypes, string>> = {}
@@ -1,70 +0,0 @@
1
- import type { Ref } from 'vue'
2
- import type { CalendarEvent } from './CalendarTypes'
3
-
4
- export interface PopoverState {
5
- activeEvent: Ref<CalendarEvent | null>
6
- showPopover: Ref<boolean>
7
- popoverPosition: Ref<{ top: number, left: number, width: number, height: number }>
8
- popoverRef: Ref<HTMLElement | null>
9
- }
10
-
11
- /**
12
- * Positions the popover to be centered on the target element and ensures it stays within viewport
13
- */
14
- export function calculatePopoverPosition(
15
- target: HTMLElement,
16
- popoverWidth = 300,
17
- popoverHeight = 150,
18
- ): { top: number, left: number, width: number, height: number } {
19
- const rect = target.getBoundingClientRect()
20
- const { scrollY, scrollX, innerHeight, innerWidth } = window
21
-
22
- // Default position (centered to the left of the element)
23
- let top = rect.top + scrollY + (rect.height / 2) - (popoverHeight / 2)
24
- let left = rect.left + scrollX + rect.width + 10
25
-
26
- // Keep popover within viewport bounds
27
- top = Math.max(scrollY + 10, Math.min(top, innerHeight + scrollY - popoverHeight - 10))
28
-
29
- // If it would go off right side, position to the left instead
30
- if (left + popoverWidth > innerWidth + scrollX) {
31
- left = rect.left + scrollX - popoverWidth - 10
32
- }
33
-
34
- // If it would go off left side, place it to the right
35
- if (left < scrollX) {
36
- left = rect.right + scrollX + 10
37
- }
38
-
39
- return { top, left, width: popoverWidth, height: popoverHeight }
40
- }
41
-
42
- /**
43
- * Opens a popover for a calendar event
44
- */
45
- export function openPopover(
46
- event: CalendarEvent,
47
- e: MouseEvent,
48
- state: PopoverState,
49
- hasEventContentSlot: boolean,
50
- emitEventClick: (event: CalendarEvent) => void
51
- ) {
52
- // Don't open if no slot provided
53
- if (!hasEventContentSlot) {
54
- emitEventClick(event)
55
- return
56
- }
57
-
58
- // Set active event and calculate position
59
- state.activeEvent.value = event
60
- state.popoverPosition.value = calculatePopoverPosition(e.currentTarget as HTMLElement)
61
- state.showPopover.value = true
62
- }
63
-
64
- /**
65
- * Closes the popover
66
- */
67
- export function closePopover(state: PopoverState) {
68
- state.showPopover.value = false
69
- state.activeEvent.value = null
70
- }