@operato/event-view 8.0.0-alpha.53 → 8.0.0-beta.1

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.
@@ -1,220 +0,0 @@
1
- import '@material/web/button/text-button.js'
2
-
3
- import dayjs, { Dayjs } from 'dayjs/esm/index'
4
- import { html, LitElement, PropertyValues } from 'lit'
5
- import { customElement, property, state } from 'lit/decorators.js'
6
-
7
- import { CalendarMonthlyStyles } from './calendar-monthly-styles'
8
- import { BizEvent, CALENDAR, WEEKDAYS, EventProvider, isToday } from './types'
9
-
10
- @customElement('calendar-monthly')
11
- export class CalendarMonthly extends LitElement {
12
- static styles = [CalendarMonthlyStyles]
13
-
14
- @property({ type: Object }) eventProvider?: EventProvider
15
-
16
- @state() year: number = dayjs().year()
17
- @state() month: number = dayjs().month()
18
- @state() calendar?: CALENDAR
19
- @state() eventMap?: Map<Date, BizEvent[]>
20
- @state() selections?: [Date, Date] | []
21
-
22
- @state() pointerDownDate?: Date | null
23
-
24
- render() {
25
- return html`
26
- <div head>
27
- <div this-month><b>${dayjs(new Date(this.year, this.month)).format('MMMM')}</b> ${this.year}</div>
28
-
29
- <div nav>
30
- <md-text-button
31
- @click=${() => {
32
- this.moveTo(dayjs(new Date(this.year, this.month, 1)).subtract(1, 'month'))
33
- }}
34
- ><</md-text-button
35
- >
36
- <md-text-button
37
- @click=${() => {
38
- this.moveTo(dayjs(new Date(dayjs().year(), dayjs().month(), 1)))
39
- }}
40
- >Today</md-text-button
41
- >
42
- <md-text-button
43
- @click=${() => {
44
- this.moveTo(dayjs(new Date(this.year, this.month, 1)).add(1, 'month'))
45
- }}
46
- >></md-text-button
47
- >
48
- </div>
49
-
50
- <slot></slot>
51
- </div>
52
-
53
- <ol
54
- @pointerdown=${this.handlePointerDown}
55
- @pointermove=${this.handlePointerMove}
56
- @pointerup=${this.handlePointerUp}
57
- >
58
- ${WEEKDAYS.map(date => html` <li day-of-week>${date}</li> `)}
59
- ${this.calendar?.map(date => {
60
- const [from, to] = this.selections || ([] as any)
61
- const { date: thisDate } = date
62
- const selected = from && to && thisDate >= from && thisDate <= to
63
-
64
- return html`
65
- <li ?today=${date.today} ?current-month=${date.thisMonth} ?selected=${selected} .date=${thisDate} date>
66
- <span date-label>${date.label}</span>
67
- <div>
68
- ${(this.eventMap?.get(date?.date) || []).map(({ title, color, template }) =>
69
- template ? template : html`<span event .style="border-color: ${color};">${title}</span>`
70
- )}
71
- </div>
72
- </li>
73
- `
74
- })}
75
- </ol>
76
- `
77
- }
78
-
79
- async updated(changes: PropertyValues<this>) {
80
- if (changes.has('year') || changes.has('month') || changes.has('eventProvider')) {
81
- const currentMonth = this.createDaysForCurrentMonth(this.year, this.month)
82
-
83
- const calendar = [
84
- ...this.createDaysForPreviousMonth(this.year, this.month, currentMonth),
85
- ...currentMonth,
86
- ...this.createDaysForNextMonth(this.year, this.month, currentMonth)
87
- ]
88
-
89
- this.eventMap = await this.eventProvider?.fetchEventsForCalendar(calendar)
90
- this.calendar = calendar
91
- }
92
- }
93
-
94
- handlePointerDown(event: PointerEvent) {
95
- const target = event.target as HTMLElement
96
-
97
- if (!target.hasAttribute('date') && !target.hasAttribute('date-label')) {
98
- return
99
- }
100
-
101
- const dateElement = target.closest('[date]') as HTMLElement
102
- const from = (dateElement as any).date
103
-
104
- this.pointerDownDate = from
105
-
106
- // 캡처를 설정하지 않음(Touch 디바이스에서 중요)
107
- target.releasePointerCapture(event.pointerId)
108
-
109
- event.preventDefault()
110
- }
111
-
112
- handlePointerMove(event: PointerEvent) {
113
- const from = this.pointerDownDate
114
-
115
- if (!from) {
116
- return
117
- }
118
-
119
- const target = event.target as HTMLElement
120
- const dateElement = target.closest('[date]') as HTMLElement
121
-
122
- if (!dateElement) {
123
- return
124
- }
125
-
126
- const date = (dateElement as any).date
127
- this.selections = from > date ? [date, from] : [from, date]
128
-
129
- // 캡처를 설정하지 않음(Touch 디바이스에서 중요)
130
- target.releasePointerCapture(event.pointerId)
131
-
132
- event.preventDefault()
133
- }
134
-
135
- handlePointerUp(event: PointerEvent) {
136
- const from = this.pointerDownDate
137
-
138
- this.pointerDownDate = null
139
-
140
- if (!from) {
141
- return
142
- }
143
-
144
- const target = event.target as HTMLElement
145
- const dateElement = target.closest('[date]') as HTMLElement
146
-
147
- if (!dateElement) {
148
- return
149
- }
150
-
151
- const date = (dateElement as any).date
152
- this.selections = from > date ? [date, from] : [from, date]
153
-
154
- this.dispatchEvent(
155
- new CustomEvent('select-date', {
156
- detail: this.selections,
157
- bubbles: true,
158
- composed: true
159
- })
160
- )
161
-
162
- event.preventDefault()
163
- }
164
-
165
- moveTo(month: Dayjs) {
166
- this.year = month.year()
167
- this.month = month.month()
168
- }
169
-
170
- createDaysForCurrentMonth(year: number, month: number): CALENDAR {
171
- return [...Array(dayjs(new Date(year, month, 1)).daysInMonth())].map((day, index) => {
172
- const date = new Date(year, month, index + 1)
173
- const label = index == 0 ? dayjs(date).format('MMM D') : dayjs(date).format('D')
174
- return {
175
- date,
176
- label,
177
- thisMonth: true,
178
- today: isToday(date)
179
- }
180
- })
181
- }
182
-
183
- createDaysForPreviousMonth(year: number, month: number, currentMonth: CALENDAR): CALENDAR {
184
- const previousMonth = dayjs(new Date(year, month, 1)).subtract(1, 'month')
185
-
186
- const visibleNumberOfDaysFromPreviousMonth = (dayjs(currentMonth[0].date) as any).weekday()
187
-
188
- const previousMonthLastMondayDayOfMonth = dayjs(currentMonth[0].date)
189
- .subtract(visibleNumberOfDaysFromPreviousMonth, 'day')
190
- .date()
191
-
192
- return [...Array(visibleNumberOfDaysFromPreviousMonth)].map((day, index) => {
193
- const date = new Date(previousMonth.year(), previousMonth.month(), previousMonthLastMondayDayOfMonth + index)
194
- const label = index == 0 ? dayjs(date).format('MMM D') : dayjs(date).format('D')
195
- return {
196
- date,
197
- label,
198
- thisMonth: false,
199
- today: isToday(date)
200
- }
201
- })
202
- }
203
-
204
- createDaysForNextMonth(year: number, month: number, currentMonth: CALENDAR): CALENDAR {
205
- const nextMonth = dayjs(new Date(year, month, 1)).add(1, 'month')
206
-
207
- const visibleNumberOfDaysFromNextMonth = 6 - (dayjs(new Date(year, month, currentMonth.length)) as any).weekday()
208
-
209
- return [...Array(visibleNumberOfDaysFromNextMonth)].map((day, index) => {
210
- const date = new Date(nextMonth.year(), nextMonth.month(), index + 1)
211
- const label = index == 0 ? dayjs(date).format('MMM D') : dayjs(date).format('D')
212
- return {
213
- date,
214
- label,
215
- thisMonth: false,
216
- today: isToday(date)
217
- }
218
- })
219
- }
220
- }
@@ -1,113 +0,0 @@
1
- import { css } from 'lit'
2
-
3
- export const CalendarWeeklyStyles = css`
4
- :host {
5
- display: flex;
6
- flex-direction: column;
7
- color: var(--calendar-weekly-text-color, #585858);
8
-
9
- --md-text-button-container-height: 24px;
10
- --md-sys-color-primary: rgba(var(--secondary-color-rgb), 0.8);
11
- }
12
-
13
- [head] {
14
- display: flex;
15
- align-items: center;
16
- }
17
-
18
- [head-week] {
19
- display: flex;
20
- align-items: left;
21
- }
22
-
23
- [this-week] {
24
- font-size: x-large;
25
- }
26
-
27
- [nav] {
28
- margin-left: auto;
29
- }
30
-
31
- ::slotted(*) {
32
- color: var(--md-sys-color-primary);
33
- }
34
-
35
- ol {
36
- flex: 1;
37
-
38
- display: grid;
39
- grid-template-columns: repeat(7, 1fr);
40
- grid-template-rows: max-content;
41
-
42
- padding: 0;
43
- margin: var(--calendar-weekly-ol-margin, 9px 0);
44
- border-top: var(--calendar-weekly-ol-top-border, 3px solid #999);
45
- }
46
-
47
- li {
48
- position: relative;
49
-
50
- list-style: none;
51
- border: var(--calendar-weekly-border, 1px solid rgba(0, 0, 0, 0.1));
52
- border-width: var(--calendar-weekly-border-width, 0 1px 1px 0px);
53
- opacity: var(--calendar-weekly-opacity);
54
-
55
- user-select: none;
56
- touch-action: none;
57
- }
58
-
59
- li:nth-child(7n + 1) {
60
- border-left-width: 1px;
61
- }
62
-
63
- li[day-of-week] {
64
- opacity: 1;
65
- background-color: var(--calendar-current-week-background-color, var(--md-sys-color-surface-variant));
66
- color: var(--calendar-current-week-color, var(--md-sys-color-on-surface));
67
- padding: var(--calendar-weekly-label-padding);
68
- text-align: center;
69
- }
70
-
71
- li[current-week] {
72
- background-color: var(--calendar-current-week-background-color, #fff);
73
- opacity: 1;
74
- }
75
-
76
- li[selected] {
77
- background-color: var(--calendar-weekly-selected-background-color, var(--md-sys-color-tertiary-container));
78
- color: var(--calendar-weekly-selected-color, var(--md-sys-color-on-tertiary-container));
79
- }
80
-
81
- span[date-label] {
82
- display: block;
83
- margin: var(--calendar-weekly-date-label-margin);
84
- text-align: var(--calendar-weekly-label-align, center);
85
- }
86
-
87
- li[today] > span[date-label] {
88
- display: inline-block;
89
- background-color: var(--calendar-weekly-date-label-background-color, #cc3300);
90
- padding: var(--calendar-weekly-date-label-padding);
91
- border-radius: var(--calendar-weekly-date-label-border-radius, 999em);
92
- color: var(--calendar-weekly-date-label-color, #fff);
93
- min-width: 16px;
94
- text-align: center;
95
- }
96
-
97
- [date] div {
98
- display: block;
99
- font-size: small;
100
- }
101
-
102
- [event] {
103
- display: block;
104
- background-color: var(--calendar-weekly-background-color);
105
- border: var(--calendar-weekly-event-border);
106
- border-width: var(--calendar-weekly-event-border-width);
107
- margin: var(--calendar-weekly-event-margin, 0 0 4px 0);
108
- padding: var(--calendar-weekly-event-padding, 2px 4px 2px 4px);
109
-
110
- user-select: all;
111
- touch-action: all;
112
- }
113
- `
@@ -1,218 +0,0 @@
1
- import '@material/web/button/text-button.js'
2
-
3
- import dayjs, { Dayjs } from 'dayjs/esm/index'
4
- import { html, LitElement, PropertyValues } from 'lit'
5
- import { customElement, property, state } from 'lit/decorators.js'
6
-
7
- import { CalendarWeeklyStyles } from './calendar-weekly-styles'
8
- import { BizEvent, CALENDAR, WEEKDAYS, EventProvider, isToday } from './types'
9
-
10
- @customElement('calendar-weekly')
11
- export class CalendarWeekly extends LitElement {
12
- static styles = [CalendarWeeklyStyles]
13
-
14
- @property({ type: Object }) eventProvider?: EventProvider
15
-
16
- @state() year: number = dayjs().year()
17
- @state() month: number = dayjs().month()
18
- @state() week: number = dayjs().week()
19
- @state() calendar?: CALENDAR
20
- @state() eventMap?: Map<Date, BizEvent[]>
21
- @state() selections?: [Date, Date]
22
-
23
- @state() pointerDownDate?: Date | null
24
-
25
- render() {
26
- return html`
27
- <div head>
28
- <div this-week>
29
- <b>${dayjs(new Date(this.year, this.month)).format('MMMM')}</b> ${this.year} <b>Week ${this.week}</b>
30
- </div>
31
-
32
- <div nav>
33
- <md-text-button
34
- @click=${() => {
35
- const dayJs = this.getLastDateOfWeek(this.year, this.week)
36
- const prevWeek = dayJs.subtract(1, 'week')
37
- this.moveTo(prevWeek.year(), prevWeek.month(), prevWeek.week())
38
- }}
39
- ><</md-text-button
40
- >
41
- <md-text-button
42
- @click=${() => {
43
- this.moveTo(dayjs().year(), dayjs().month(), dayjs().week())
44
- }}
45
- >Today</md-text-button
46
- >
47
- <md-text-button
48
- @click=${() => {
49
- const dayJs = this.getLastDateOfWeek(this.year, this.week)
50
- const nextWeek = dayJs.add(1, 'week')
51
- this.moveTo(nextWeek.year(), nextWeek.month(), nextWeek.week())
52
- }}
53
- >></md-text-button
54
- >
55
- </div>
56
-
57
- <slot></slot>
58
- </div>
59
-
60
- <ol
61
- @pointerdown=${this.handlePointerDown}
62
- @pointermove=${this.handlePointerMove}
63
- @pointerup=${this.handlePointerUp}
64
- >
65
- ${this.calendar?.map((date, index) => {
66
- const [from, to] = this.selections || ([] as any)
67
- const { date: thisDate } = date
68
- const selected = from && to && thisDate >= from && thisDate <= to
69
-
70
- return html`
71
- <li ?today=${date.today} day-of-week date .date=${thisDate} ?selected=${selected}>
72
- <span date-label>${date.label}(${WEEKDAYS[index]})</span>
73
- </li>
74
- `
75
- })}
76
- ${this.calendar?.map(date => {
77
- const [from, to] = this.selections || ([] as any)
78
- const { date: thisDate } = date
79
- const selected = from && to && thisDate >= from && thisDate <= to
80
-
81
- return html`<li date .date=${thisDate} ?selected=${selected}>
82
- <div>
83
- ${(this.eventMap?.get(date?.date) || []).map(({ title, color, template }) =>
84
- template ? template : html`<span event .style="border-color: ${color};">${title}</span>`
85
- )}
86
- </div>
87
- </li>`
88
- })}
89
- </ol>
90
- `
91
- }
92
-
93
- async updated(changes: PropertyValues<this>) {
94
- if (changes.has('year') || changes.has('month') || changes.has('week') || changes.has('eventProvider')) {
95
- const calendar = this.createDaysForCurrentWeek(this.year, this.week)
96
-
97
- this.eventMap = await this.eventProvider?.fetchEventsForCalendar(calendar)
98
- this.calendar = calendar
99
- }
100
- }
101
-
102
- moveTo(year: number, month: number, week: number) {
103
- this.year = year
104
- this.month = month
105
- this.week = week
106
- }
107
-
108
- handlePointerDown(event: PointerEvent) {
109
- const target = event.target as HTMLElement
110
-
111
- if (!target.hasAttribute('date') && !target.hasAttribute('date-label')) {
112
- return
113
- }
114
-
115
- const dateElement = target.closest('[date]') as HTMLElement
116
- const from = (dateElement as any).date
117
-
118
- this.pointerDownDate = from
119
-
120
- // 캡처를 설정하지 않음(Touch 디바이스에서 중요)
121
- target.releasePointerCapture(event.pointerId)
122
-
123
- event.preventDefault()
124
- }
125
-
126
- handlePointerMove(event: PointerEvent) {
127
- const from = this.pointerDownDate
128
-
129
- if (!from) {
130
- return
131
- }
132
-
133
- const target = event.target as HTMLElement
134
- const dateElement = target.closest('[date]') as HTMLElement
135
-
136
- if (!dateElement) {
137
- return
138
- }
139
-
140
- const date = (dateElement as any).date
141
- this.selections = from > date ? [date, from] : [from, date]
142
-
143
- // 캡처를 설정하지 않음(Touch 디바이스에서 중요)
144
- target.releasePointerCapture(event.pointerId)
145
-
146
- event.preventDefault()
147
- }
148
-
149
- handlePointerUp(event: PointerEvent) {
150
- const from = this.pointerDownDate
151
-
152
- this.pointerDownDate = null
153
-
154
- if (!from) {
155
- return
156
- }
157
-
158
- const target = event.target as HTMLElement
159
- const dateElement = target.closest('[date]') as HTMLElement
160
-
161
- if (!dateElement) {
162
- return
163
- }
164
-
165
- const date = (dateElement as any).date
166
- this.selections = from > date ? [date, from] : [from, date]
167
-
168
- this.dispatchEvent(
169
- new CustomEvent('select-date', {
170
- detail: this.selections,
171
- bubbles: true,
172
- composed: true
173
- })
174
- )
175
-
176
- event.preventDefault()
177
- }
178
-
179
- selectDate(date: { label: string; date: Date; thisMonth?: boolean; thisWeek?: boolean; today?: boolean }) {
180
- if (date) {
181
- this.selections = [date.date, date.date]
182
- } else {
183
- this.selections = undefined
184
- }
185
-
186
- this.dispatchEvent(
187
- new CustomEvent('select-date', {
188
- detail: date,
189
- bubbles: true,
190
- composed: true
191
- })
192
- )
193
- }
194
-
195
- getLastDateOfWeek(year: number, week: number): Dayjs {
196
- const firstWeekLastDay = dayjs(new Date(year, 0, 1)).endOf('w')
197
- week -= 1 // one-based week, so need the minus-one
198
- return firstWeekLastDay.add(week, 'w')
199
- }
200
-
201
- createDaysForCurrentWeek(year: number, week: number): CALENDAR {
202
- const lastDayjs = this.getLastDateOfWeek(year, week)
203
- const weekDays = 7
204
-
205
- return [...Array(weekDays)]
206
- .map((day, index) => {
207
- const date = new Date(lastDayjs.year(), lastDayjs.month(), lastDayjs.date() - index)
208
- const label = dayjs(date).format('MM-DD')
209
- return {
210
- date,
211
- label,
212
- thisWeek: true,
213
- today: isToday(date)
214
- }
215
- })
216
- .reverse()
217
- }
218
- }
package/src/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './types.js'
2
- export * from './ox-event-view.js'
@@ -1,47 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
-
3
- import './calendar-monthly'
4
- import './calendar-weekly'
5
-
6
- import { css, html, LitElement } from 'lit'
7
- import { customElement, property } from 'lit/decorators.js'
8
-
9
- import { EventProvider } from './types'
10
-
11
- @customElement('ox-event-view')
12
- export class OxEventView extends LitElement {
13
- static styles = css`
14
- :host {
15
- display: flex;
16
- flex-direction: column;
17
-
18
- background-color: var(--md-sys-color-background);
19
- color: var(--md-sys-color-on-background);
20
- }
21
-
22
- calendar-weekly,
23
- calendar-monthly {
24
- flex: 1;
25
-
26
- padding: 0;
27
- margin: 0;
28
- }
29
- `
30
-
31
- @property({ type: String }) mode: 'monthly' | 'weekly' = 'monthly'
32
- @property({ type: Object }) eventProvider?: EventProvider
33
-
34
- render() {
35
- return this.mode == 'weekly'
36
- ? html`
37
- <calendar-weekly .eventProvider=${this.eventProvider}>
38
- <md-icon @click=${(e: Event) => (this.mode = 'monthly')}>calendar_month</md-icon>
39
- </calendar-weekly>
40
- `
41
- : html`
42
- <calendar-monthly .eventProvider=${this.eventProvider}>
43
- <md-icon @click=${(e: Event) => (this.mode = 'weekly')}>calendar_view_week</md-icon>
44
- </calendar-monthly>
45
- `
46
- }
47
- }
package/src/types.ts DELETED
@@ -1,38 +0,0 @@
1
- import { TemplateResult } from 'lit'
2
- import dayjs from 'dayjs/esm/index'
3
- import weekday from 'dayjs/esm/plugin/weekday'
4
- import weekOfYear from 'dayjs/esm/plugin/weekOfYear'
5
-
6
- dayjs.extend(weekday)
7
- dayjs.extend(weekOfYear)
8
-
9
- export type BizEvent = {
10
- due?: string
11
- title: string
12
- color: string
13
- clickEvent?: any
14
- template?: TemplateResult
15
- }
16
-
17
- export type CALENDAR = {
18
- label: string
19
- date: Date
20
- thisMonth?: boolean
21
- thisWeek?: boolean
22
- today?: boolean
23
- }[]
24
-
25
- export interface EventProvider {
26
- fetchEventsForCalendar(calendar: CALENDAR): Promise<Map<Date, BizEvent[]>>
27
- }
28
-
29
- export const WEEKDAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
30
-
31
- export function isToday(date: Date) {
32
- const today = new Date()
33
- return (
34
- date.getDate() == today.getDate() &&
35
- date.getMonth() == today.getMonth() &&
36
- date.getFullYear() == today.getFullYear()
37
- )
38
- }