@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.
- package/dist/components/calendar/CalendarPopover.vue.d.ts +179 -0
- package/dist/components/calendar/CalendarPopover.vue.d.ts.map +1 -0
- package/dist/components/calendar/CalendarTypes.d.ts +15 -0
- package/dist/components/calendar/CalendarTypes.d.ts.map +1 -1
- package/dist/components/calendar/Index.vue.d.ts +21 -12
- package/dist/components/calendar/Index.vue.d.ts.map +1 -1
- package/dist/components/calendar/views/AgendaView.vue.d.ts +8 -0
- package/dist/components/calendar/views/AgendaView.vue.d.ts.map +1 -1
- package/dist/components/calendar/views/CalendarPopover.vue.d.ts +175 -0
- package/dist/components/calendar/views/CalendarPopover.vue.d.ts.map +1 -0
- package/dist/components/calendar/views/DayView.vue.d.ts +10 -32
- package/dist/components/calendar/views/DayView.vue.d.ts.map +1 -1
- package/dist/components/calendar/views/MonthView.vue.d.ts +10 -170
- package/dist/components/calendar/views/MonthView.vue.d.ts.map +1 -1
- package/dist/components/calendar/views/WeekView.vue.d.ts +12 -168
- package/dist/components/calendar/views/WeekView.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/DatePicker.vue.d.ts.map +1 -1
- package/dist/composables/useDevice.d.ts +3 -0
- package/dist/composables/useDevice.d.ts.map +1 -1
- package/dist/index.cjs +446 -309
- package/dist/index.mjs +446 -309
- package/dist/style.css +231 -179
- package/dist/types/BagelForm.d.ts +14 -11
- package/dist/types/BagelForm.d.ts.map +1 -1
- package/dist/utils/BagelFormUtils.d.ts +10 -10
- package/dist/utils/BagelFormUtils.d.ts.map +1 -1
- package/dist/utils/calendar/dateUtils.d.ts +10 -10
- package/dist/utils/calendar/dateUtils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/calendar/CalendarPopover.vue +102 -0
- package/src/components/calendar/CalendarTypes.ts +14 -0
- package/src/components/calendar/Index.vue +77 -35
- package/src/components/calendar/views/AgendaView.vue +26 -2
- package/src/components/calendar/views/DayView.vue +83 -104
- package/src/components/calendar/views/MonthView.vue +39 -67
- package/src/components/calendar/views/WeekView.vue +229 -136
- package/src/components/form/inputs/DateInput.vue +14 -3
- package/src/components/form/inputs/DatePicker.vue +7 -0
- package/src/composables/useDevice.ts +13 -2
- package/src/styles/layout.css +14 -0
- package/src/styles/mobilLayout.css +12 -0
- package/src/types/BagelForm.ts +30 -53
- package/src/utils/BagelFormUtils.ts +11 -10
- package/src/utils/calendar/dateUtils.ts +42 -45
- 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,
|
package/src/types/BagelForm.ts
CHANGED
|
@@ -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
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
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
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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 {
|
|
17
|
-
if (
|
|
18
|
-
date.setDate(date.getDate() +
|
|
16
|
+
const { Day, Hour, Minute, Second, Week, Month, Year } = options
|
|
17
|
+
if (Day) {
|
|
18
|
+
date.setDate(date.getDate() + Day)
|
|
19
19
|
}
|
|
20
|
-
if (
|
|
21
|
-
date.setHours(date.getHours() +
|
|
20
|
+
if (Hour) {
|
|
21
|
+
date.setHours(date.getHours() + Hour)
|
|
22
22
|
}
|
|
23
|
-
if (
|
|
24
|
-
date.setMinutes(date.getMinutes() +
|
|
23
|
+
if (Minute) {
|
|
24
|
+
date.setMinutes(date.getMinutes() + Minute)
|
|
25
25
|
}
|
|
26
|
-
if (
|
|
27
|
-
date.setSeconds(date.getSeconds() +
|
|
26
|
+
if (Second) {
|
|
27
|
+
date.setSeconds(date.getSeconds() + Second)
|
|
28
28
|
}
|
|
29
|
-
if (
|
|
30
|
-
date.setDate(date.getDate() +
|
|
29
|
+
if (Week) {
|
|
30
|
+
date.setDate(date.getDate() + Week * 7)
|
|
31
31
|
}
|
|
32
|
-
if (
|
|
33
|
-
date.setMonth(date.getMonth() +
|
|
32
|
+
if (Month) {
|
|
33
|
+
date.setMonth(date.getMonth() + Month)
|
|
34
34
|
}
|
|
35
|
-
if (
|
|
36
|
-
date.setFullYear(date.getFullYear() +
|
|
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,
|
|
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(
|
|
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,
|
|
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,
|
|
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
|
|
273
|
+
const intFmtOpt: Intl.DateTimeFormatOptions = {
|
|
284
274
|
day: 'numeric',
|
|
285
275
|
hour: '2-digit',
|
|
286
|
-
|
|
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
|
-
}
|