@operato/event-view 10.10.2 → 10.15.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/coverage/lcov-report/index.html +66 -21
  3. package/coverage/lcov.info +6394 -3195
  4. package/dist/src/calendar-monthly-styles.js +242 -12
  5. package/dist/src/calendar-monthly-styles.js.map +1 -1
  6. package/dist/src/calendar-monthly.d.ts +8 -1
  7. package/dist/src/calendar-monthly.js +90 -17
  8. package/dist/src/calendar-monthly.js.map +1 -1
  9. package/dist/src/calendar-weekly-styles.js +136 -13
  10. package/dist/src/calendar-weekly-styles.js.map +1 -1
  11. package/dist/src/calendar-weekly.d.ts +8 -1
  12. package/dist/src/calendar-weekly.js +92 -12
  13. package/dist/src/calendar-weekly.js.map +1 -1
  14. package/dist/src/day-overflow.d.ts +42 -0
  15. package/dist/src/day-overflow.js +71 -0
  16. package/dist/src/day-overflow.js.map +1 -0
  17. package/dist/src/index.d.ts +1 -0
  18. package/dist/src/index.js +1 -0
  19. package/dist/src/index.js.map +1 -1
  20. package/dist/src/ox-event-view.d.ts +3 -0
  21. package/dist/src/ox-event-view.js +33 -2
  22. package/dist/src/ox-event-view.js.map +1 -1
  23. package/dist/src/types.d.ts +66 -1
  24. package/dist/src/types.js +64 -1
  25. package/dist/src/types.js.map +1 -1
  26. package/dist/test/calendar-layout.test.js +102 -0
  27. package/dist/test/calendar-layout.test.js.map +1 -1
  28. package/dist/test/day-overflow.test.d.ts +1 -0
  29. package/dist/test/day-overflow.test.js +81 -0
  30. package/dist/test/day-overflow.test.js.map +1 -0
  31. package/dist/test/day-state.test.d.ts +1 -0
  32. package/dist/test/day-state.test.js +115 -0
  33. package/dist/test/day-state.test.js.map +1 -0
  34. package/dist/tsconfig.tsbuildinfo +1 -1
  35. package/package.json +4 -3
  36. package/test/calendar-layout.test.ts +130 -0
  37. package/test/day-overflow.test.ts +103 -0
  38. package/test/day-state.test.ts +139 -0
@@ -1 +1 @@
1
- {"version":3,"file":"calendar-monthly.js","sourceRoot":"","sources":["../../src/calendar-monthly.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/text-button.js'\n\nimport dayjs, { Dayjs } from 'dayjs/esm/index.js'\nimport { html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { CalendarMonthlyStyles } from './calendar-monthly-styles.js'\nimport { BizEvent, CALENDAR, WEEKDAYS, EventProvider, isToday } from './types.js'\n\n@customElement('calendar-monthly')\nexport class CalendarMonthly extends LitElement {\n static styles = [CalendarMonthlyStyles]\n\n @property({ type: Object }) eventProvider?: EventProvider\n\n @state() year: number = dayjs().year()\n @state() month: number = dayjs().month()\n @state() calendar?: CALENDAR\n @state() eventMap?: Map<Date, BizEvent[]>\n @state() selections?: [Date, Date] | []\n\n @state() pointerDownDate?: Date | null\n\n render() {\n return html`\n <div head>\n <div this-month><b>${dayjs(new Date(this.year, this.month)).format('MMMM')}</b> ${this.year}</div>\n\n <div nav>\n <md-text-button\n @click=${() => {\n this.moveTo(dayjs(new Date(this.year, this.month, 1)).subtract(1, 'month'))\n }}\n ><</md-text-button\n >\n <md-text-button\n @click=${() => {\n this.moveTo(dayjs(new Date(dayjs().year(), dayjs().month(), 1)))\n }}\n >Today</md-text-button\n >\n <md-text-button\n @click=${() => {\n this.moveTo(dayjs(new Date(this.year, this.month, 1)).add(1, 'month'))\n }}\n >></md-text-button\n >\n </div>\n\n <slot></slot>\n </div>\n\n <ol\n @pointerdown=${this.handlePointerDown}\n @pointermove=${this.handlePointerMove}\n @pointerup=${this.handlePointerUp}\n >\n ${WEEKDAYS.map(date => html` <li day-of-week>${date}</li> `)}\n ${this.calendar?.map(date => {\n const [from, to] = this.selections || ([] as any)\n const { date: thisDate } = date\n const selected = from && to && thisDate >= from && thisDate <= to\n\n return html`\n <li ?today=${date.today} ?current-month=${date.thisMonth} ?selected=${selected} .date=${thisDate} date>\n <span date-label>${date.label}</span>\n <div>\n ${(this.eventMap?.get(date?.date) || []).map(({ title, color, template }) =>\n template ? template : html`<span event .style=\"border-color: ${color};\">${title}</span>`\n )}\n </div>\n </li>\n `\n })}\n </ol>\n `\n }\n\n async updated(changes: PropertyValues<this>) {\n if (changes.has('year') || changes.has('month') || changes.has('eventProvider')) {\n const currentMonth = this.createDaysForCurrentMonth(this.year, this.month)\n\n const calendar = [\n ...this.createDaysForPreviousMonth(this.year, this.month, currentMonth),\n ...currentMonth,\n ...this.createDaysForNextMonth(this.year, this.month, currentMonth)\n ]\n\n this.eventMap = await this.eventProvider?.fetchEventsForCalendar(calendar)\n this.calendar = calendar\n }\n }\n\n handlePointerDown(event: PointerEvent) {\n const target = event.target as HTMLElement\n\n if (!target.hasAttribute('date') && !target.hasAttribute('date-label')) {\n return\n }\n\n const dateElement = target.closest('[date]') as HTMLElement\n const from = (dateElement as any).date\n\n this.pointerDownDate = from\n\n // 캡처를 설정하지 않음(Touch 디바이스에서 중요)\n target.releasePointerCapture(event.pointerId)\n\n event.preventDefault()\n }\n\n handlePointerMove(event: PointerEvent) {\n const from = this.pointerDownDate\n\n if (!from) {\n return\n }\n\n const target = event.target as HTMLElement\n const dateElement = target.closest('[date]') as HTMLElement\n\n if (!dateElement) {\n return\n }\n\n const date = (dateElement as any).date\n this.selections = from > date ? [date, from] : [from, date]\n\n // 캡처를 설정하지 않음(Touch 디바이스에서 중요)\n target.releasePointerCapture(event.pointerId)\n\n event.preventDefault()\n }\n\n handlePointerUp(event: PointerEvent) {\n const from = this.pointerDownDate\n\n this.pointerDownDate = null\n\n if (!from) {\n return\n }\n\n const target = event.target as HTMLElement\n const dateElement = target.closest('[date]') as HTMLElement\n\n if (!dateElement) {\n return\n }\n\n const date = (dateElement as any).date\n this.selections = from > date ? [date, from] : [from, date]\n\n this.dispatchEvent(\n new CustomEvent('select-date', {\n detail: this.selections,\n bubbles: true,\n composed: true\n })\n )\n\n event.preventDefault()\n }\n\n moveTo(month: Dayjs) {\n this.year = month.year()\n this.month = month.month()\n\n this.dispatchEvent(\n new CustomEvent('change-month', {\n detail: { year: this.year, month: this.month + 1 }, // 0~11월이라 +1 해서 이벤트 전파\n bubbles: true,\n composed: true\n })\n )\n }\n\n createDaysForCurrentMonth(year: number, month: number): CALENDAR {\n return [...Array(dayjs(new Date(year, month, 1)).daysInMonth())].map((day, index) => {\n const date = new Date(year, month, index + 1)\n const label = index == 0 ? dayjs(date).format('MMM D') : dayjs(date).format('D')\n return {\n date,\n label,\n thisMonth: true,\n today: isToday(date)\n }\n })\n }\n\n createDaysForPreviousMonth(year: number, month: number, currentMonth: CALENDAR): CALENDAR {\n const previousMonth = dayjs(new Date(year, month, 1)).subtract(1, 'month')\n\n const visibleNumberOfDaysFromPreviousMonth = (dayjs(currentMonth[0].date) as any).weekday()\n\n const previousMonthLastMondayDayOfMonth = dayjs(currentMonth[0].date)\n .subtract(visibleNumberOfDaysFromPreviousMonth, 'day')\n .date()\n\n return [...Array(visibleNumberOfDaysFromPreviousMonth)].map((day, index) => {\n const date = new Date(previousMonth.year(), previousMonth.month(), previousMonthLastMondayDayOfMonth + index)\n const label = index == 0 ? dayjs(date).format('MMM D') : dayjs(date).format('D')\n return {\n date,\n label,\n thisMonth: false,\n today: isToday(date)\n }\n })\n }\n\n createDaysForNextMonth(year: number, month: number, currentMonth: CALENDAR): CALENDAR {\n const nextMonth = dayjs(new Date(year, month, 1)).add(1, 'month')\n\n const visibleNumberOfDaysFromNextMonth = 6 - (dayjs(new Date(year, month, currentMonth.length)) as any).weekday()\n\n return [...Array(visibleNumberOfDaysFromNextMonth)].map((day, index) => {\n const date = new Date(nextMonth.year(), nextMonth.month(), index + 1)\n const label = index == 0 ? dayjs(date).format('MMM D') : dayjs(date).format('D')\n return {\n date,\n label,\n thisMonth: false,\n today: isToday(date)\n }\n })\n }\n}\n"]}
1
+ {"version":3,"file":"calendar-monthly.js","sourceRoot":"","sources":["../../src/calendar-monthly.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/text-button.js'\nimport '@material/web/iconbutton/icon-button.js'\nimport '@material/web/icon/icon.js'\n\nimport dayjs, { Dayjs } from 'dayjs/esm/index.js'\nimport { html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\nimport { TooltipReactiveController } from '@operato/utils'\n\nimport { CalendarMonthlyStyles } from './calendar-monthly-styles.js'\nimport { reportDayOverflow } from './day-overflow.js'\nimport {\n BizEvent,\n CALENDAR,\n DayState,\n EventProvider,\n isToday,\n dayLabel,\n monthTitle,\n nextMonthLabel,\n previousMonthLabel,\n todayLabel,\n weekdayNames\n} from './types.js'\n\n@customElement('calendar-monthly')\nexport class CalendarMonthly extends LitElement {\n static styles = [CalendarMonthlyStyles]\n\n @property({ type: Object }) eventProvider?: EventProvider\n\n @state() year: number = dayjs().year()\n @state() month: number = dayjs().month()\n @state() calendar?: CALENDAR\n @state() eventMap?: Map<Date, BizEvent[]>\n /** What is true of the days themselves, if the host answers for them. See {@link DayState}. */\n @state() dayStateMap?: Map<Date, DayState>\n @state() selections?: [Date, Date] | []\n\n @state() pointerDownDate?: Date | null\n\n /** Last reported overflow, so the host is not told the same thing after every render. */\n private lastOverflow = ''\n\n /*\n * Event titles are drawn on one nowrap line and cut with an ellipsis, so the full name only\n * exists in a tooltip. Hosts were reaching for the browser's own `title`, which waits about a\n * second and cannot be styled — measured on the plant calendar.\n *\n * data-grist already runs this controller on its header and its cells. It waits 450ms so a\n * pointer crossing the grid does not trail tooltips behind it, then drops the wait once one\n * is up, and it only fires on elements that actually overflow — which is exactly the set of\n * titles worth expanding.\n *\n * Hosts mark the rows they want expanded with data-reactive-tooltip. The listener sits on\n * this shadow root, where the host's own event templates are rendered.\n */\n private tooltip = new TooltipReactiveController(this, {\n /*\n * Read the attribute's value, not the row's text.\n *\n * The controller treats the attribute as a marker and otherwise repeats what is already on\n * screen, which for a cut title is at least the whole title. But a host writes the line it\n * wants read - the plant calendar puts the kind, the order and where it runs in there - and\n * without this that sentence was thrown away. [확인함] 2026-09-11\n */\n content: element => element.getAttribute('data-reactive-tooltip') || element.textContent?.trim() || ''\n })\n\n render() {\n return html`\n <div head>\n <div this-month>${monthTitle(this.year, this.month)}</div>\n\n <div nav>\n <!--\n Chevrons, not the \"<\" and \">\" characters that were here. Those are text: they take\n the text colour and weight, sit on the text baseline, and a screen reader says\n \"less than\". An icon button is also a target, which the bare glyph was not.\n -->\n <md-icon-button\n aria-label=${previousMonthLabel()}\n title=${previousMonthLabel()}\n @click=${() => {\n this.moveTo(dayjs(new Date(this.year, this.month, 1)).subtract(1, 'month'))\n }}\n >\n <md-icon>chevron_left</md-icon>\n </md-icon-button>\n <md-text-button\n @click=${() => {\n this.moveTo(dayjs(new Date(dayjs().year(), dayjs().month(), 1)))\n }}\n >${todayLabel()}</md-text-button\n >\n <md-icon-button\n aria-label=${nextMonthLabel()}\n title=${nextMonthLabel()}\n @click=${() => {\n this.moveTo(dayjs(new Date(this.year, this.month, 1)).add(1, 'month'))\n }}\n >\n <md-icon>chevron_right</md-icon>\n </md-icon-button>\n </div>\n\n <slot></slot>\n </div>\n\n <ol\n @pointerdown=${this.handlePointerDown}\n @pointermove=${this.handlePointerMove}\n @pointerup=${this.handlePointerUp}\n >\n ${weekdayNames().map(name => html` <li day-of-week>${name}</li> `)}\n ${this.calendar?.map(date => {\n const [from, to] = this.selections || ([] as any)\n const { date: thisDate } = date\n const selected = from && to && thisDate >= from && thisDate <= to\n const dayState = this.dayStateMap?.get(thisDate)\n\n return html`\n <li\n ?today=${date.today}\n ?current-month=${date.thisMonth}\n ?selected=${selected}\n day-state=${ifDefined(dayState?.name)}\n style=${ifDefined(dayState && `--day-state-color:${dayState.color}`)}\n .date=${thisDate}\n date\n >\n <span date-label>${dayLabel(date.date, !!date.withMonth)}</span>\n <div>\n ${(this.eventMap?.get(date?.date) || []).map(({ title, color, template }) =>\n template ? template : html`<span event .style=\"border-color: ${color};\">${title}</span>`\n )}\n </div>\n </li>\n `\n })}\n </ol>\n `\n }\n\n async updated(changes: PropertyValues<this>) {\n if (changes.has('year') || changes.has('month') || changes.has('eventProvider')) {\n const currentMonth = this.createDaysForCurrentMonth(this.year, this.month)\n\n const calendar = [\n ...this.createDaysForPreviousMonth(this.year, this.month, currentMonth),\n ...currentMonth,\n ...this.createDaysForNextMonth(this.year, this.month, currentMonth)\n ]\n\n /*\n * Both questions go out together. A host that keeps the day's events and the day's own\n * state in one place answers both from one round trip, and the two always describe the\n * same grid - asking them apart would let a month change land between them.\n */\n const [eventMap, dayStateMap] = await Promise.all([\n this.eventProvider?.fetchEventsForCalendar(calendar),\n this.eventProvider?.fetchDayStatesForCalendar?.(calendar)\n ])\n\n this.eventMap = eventMap\n this.dayStateMap = dayStateMap\n this.calendar = calendar\n }\n\n /*\n * After the rows are laid out, not before. A cap only bites once the browser has placed the\n * children, so this has to run on every render - the grid also reflows when the host swaps\n * its templates or the window changes width.\n */\n this.lastOverflow = reportDayOverflow(this, this.shadowRoot, this.lastOverflow)\n }\n\n handlePointerDown(event: PointerEvent) {\n const target = event.target as HTMLElement\n\n if (!target.hasAttribute('date') && !target.hasAttribute('date-label')) {\n return\n }\n\n const dateElement = target.closest('[date]') as HTMLElement\n const from = (dateElement as any).date\n\n this.pointerDownDate = from\n\n // 캡처를 설정하지 않음(Touch 디바이스에서 중요)\n target.releasePointerCapture(event.pointerId)\n\n event.preventDefault()\n }\n\n handlePointerMove(event: PointerEvent) {\n const from = this.pointerDownDate\n\n if (!from) {\n return\n }\n\n const target = event.target as HTMLElement\n const dateElement = target.closest('[date]') as HTMLElement\n\n if (!dateElement) {\n return\n }\n\n const date = (dateElement as any).date\n this.selections = from > date ? [date, from] : [from, date]\n\n // 캡처를 설정하지 않음(Touch 디바이스에서 중요)\n target.releasePointerCapture(event.pointerId)\n\n event.preventDefault()\n }\n\n handlePointerUp(event: PointerEvent) {\n const from = this.pointerDownDate\n\n this.pointerDownDate = null\n\n if (!from) {\n return\n }\n\n const target = event.target as HTMLElement\n const dateElement = target.closest('[date]') as HTMLElement\n\n if (!dateElement) {\n return\n }\n\n const date = (dateElement as any).date\n this.selections = from > date ? [date, from] : [from, date]\n\n this.dispatchEvent(\n new CustomEvent('select-date', {\n detail: this.selections,\n bubbles: true,\n composed: true\n })\n )\n\n event.preventDefault()\n }\n\n moveTo(month: Dayjs) {\n this.year = month.year()\n this.month = month.month()\n\n this.dispatchEvent(\n new CustomEvent('change-month', {\n detail: { year: this.year, month: this.month + 1 }, // 0~11월이라 +1 해서 이벤트 전파\n bubbles: true,\n composed: true\n })\n )\n }\n\n createDaysForCurrentMonth(year: number, month: number): CALENDAR {\n return [...Array(dayjs(new Date(year, month, 1)).daysInMonth())].map((day, index) => {\n const date = new Date(year, month, index + 1)\n const withMonth = index == 0\n return {\n date,\n label: dayLabel(date, withMonth),\n withMonth,\n thisMonth: true,\n today: isToday(date)\n }\n })\n }\n\n createDaysForPreviousMonth(year: number, month: number, currentMonth: CALENDAR): CALENDAR {\n const previousMonth = dayjs(new Date(year, month, 1)).subtract(1, 'month')\n\n const visibleNumberOfDaysFromPreviousMonth = (dayjs(currentMonth[0].date) as any).weekday()\n\n const previousMonthLastMondayDayOfMonth = dayjs(currentMonth[0].date)\n .subtract(visibleNumberOfDaysFromPreviousMonth, 'day')\n .date()\n\n return [...Array(visibleNumberOfDaysFromPreviousMonth)].map((day, index) => {\n const date = new Date(previousMonth.year(), previousMonth.month(), previousMonthLastMondayDayOfMonth + index)\n const withMonth = index == 0\n return {\n date,\n label: dayLabel(date, withMonth),\n withMonth,\n thisMonth: false,\n today: isToday(date)\n }\n })\n }\n\n createDaysForNextMonth(year: number, month: number, currentMonth: CALENDAR): CALENDAR {\n const nextMonth = dayjs(new Date(year, month, 1)).add(1, 'month')\n\n const visibleNumberOfDaysFromNextMonth = 6 - (dayjs(new Date(year, month, currentMonth.length)) as any).weekday()\n\n return [...Array(visibleNumberOfDaysFromNextMonth)].map((day, index) => {\n const date = new Date(nextMonth.year(), nextMonth.month(), index + 1)\n const withMonth = index == 0\n return {\n date,\n label: dayLabel(date, withMonth),\n withMonth,\n thisMonth: false,\n today: isToday(date)\n }\n })\n }\n}\n"]}
@@ -5,12 +5,26 @@ export const CalendarWeeklyStyles = css `
5
5
  flex-direction: column;
6
6
  color: var(--calendar-weekly-text-color, var(--md-sys-color-on-surface-variant, #585858));
7
7
 
8
- --md-text-button-container-height: 24px;
8
+ /*
9
+ One row of controls, one height. The text button was pinned to 24px while the icon
10
+ buttons beside it are 40, so the middle of the three sat in a different band.
11
+ */
12
+ --md-text-button-container-height: 32px;
13
+ --md-icon-button-icon-size: 20px;
14
+ --md-icon-button-state-layer-height: 32px;
15
+ --md-icon-button-state-layer-width: 32px;
9
16
  }
10
17
 
11
18
  [head] {
12
19
  display: flex;
13
20
  align-items: center;
21
+ /*
22
+ The view switch sat flush against the next button — measured 0px between them.
23
+
24
+ The space goes on the switch, not on the row: a flex gap also opens a gap between the
25
+ title and the nav, and those two extra pixels each made the header 8px wider than the
26
+ grid under it, which put a horizontal scrollbar on the whole calendar. [확인함] 2026-09-11
27
+ */
14
28
  }
15
29
 
16
30
  [head-week] {
@@ -22,12 +36,41 @@ export const CalendarWeeklyStyles = css `
22
36
  [this-week] {
23
37
  /* Was the x-large keyword, which is a browser step, not a step of this theme. */
24
38
  font-size: var(--md-sys-typescale-headline-small-size, 1.5rem);
39
+ /*
40
+ The month used to be wrapped in <b>. Formatting the whole title through Intl dropped
41
+ that tag and left 24px at weight 400 — large, but with nothing to say it is the title.
42
+ */
43
+ font-weight: var(--md-sys-typescale-headline-small-weight, 640);
44
+ /*
45
+ The header must never be what makes the calendar scroll sideways. A flex item's floor is
46
+ its content, so without this the title pushes the nav out and the grid follows — the same
47
+ rule the day cells needed.
48
+ */
49
+ min-width: 0;
50
+ overflow: hidden;
51
+ text-overflow: ellipsis;
52
+ white-space: nowrap;
25
53
  }
26
54
 
27
55
  [nav] {
28
56
  margin-left: auto;
29
57
  }
30
58
 
59
+ /*
60
+ Room for what the buttons actually occupy.
61
+
62
+ An md-icon-button paints a 48px touch target around its 32px box, so the rightmost control
63
+ reaches 8px past its own edge. With that control flush to the header's right edge the
64
+ header measured 8px wider than the grid under it, and the whole calendar grew a horizontal
65
+ scrollbar. [확인함] 2026-09-11 — button right 898, its inner target 906, header client 860.
66
+
67
+ The inset makes room instead of shrinking the target: a smaller target is a worse button,
68
+ and the last control here is slotted by the host, whose size this component cannot know.
69
+ */
70
+ [head] {
71
+ padding-right: var(--calendar-head-inset, 8px);
72
+ }
73
+
31
74
  /*
32
75
  * Same token the monthly view uses for its slotted switch.
33
76
  *
@@ -56,6 +99,9 @@ export const CalendarWeeklyStyles = css `
56
99
  padding: 0;
57
100
  margin: var(--calendar-weekly-ol-margin, 9px 0);
58
101
  border-top: var(--calendar-weekly-ol-top-border, 3px solid var(--md-sys-color-outline, #999));
102
+ /* Same as the month view — the grid is one box and closes its own corners. */
103
+ border-radius: var(--calendar-weekly-radius, var(--ui-r-small, 6px));
104
+ overflow: hidden;
59
105
  }
60
106
 
61
107
  /*
@@ -88,42 +134,119 @@ export const CalendarWeeklyStyles = css `
88
134
 
89
135
  li[day-of-week] {
90
136
  opacity: 1;
91
- background-color: var(--calendar-current-week-background-color, var(--md-sys-color-surface-variant));
137
+ background-color: var(--calendar-current-week-background-color, var(--md-sys-color-surface));
92
138
  color: var(--calendar-current-week-color, var(--md-sys-color-on-surface));
93
139
  padding: var(--calendar-weekly-label-padding);
94
140
  text-align: center;
95
141
  }
96
142
 
97
- li[current-week] {
98
- background-color: var(--calendar-current-week-background-color, var(--md-sys-color-surface, #fff));
99
- opacity: 1;
143
+ /*
144
+ The cells that hold the events.
145
+
146
+ They carried no surface at all. This view draws two rows of seven - the dates on top, the
147
+ events under them - and only the date row was painted, by the rule above. The event row was
148
+ transparent, so it showed whatever the host put behind the calendar, which on the plant page
149
+ is the same colour as the date band. [확인함] 2026-09-11 — both measured rgb(240,242,244),
150
+ and the outer box behind them the same again.
151
+
152
+ So the week view never got the separation the month view has: there, the days you are
153
+ reading are the brightest surface and the band above them is a step down. Same ladder here.
154
+
155
+ A rule for li[current-week] used to sit in this place. Nothing has ever carried that
156
+ attribute - the markup writes day-of-week on the date row and nothing on this one - so it
157
+ painted nothing, while reading the token that the date band above actually uses.
158
+ */
159
+ li[date]:not([day-of-week]) {
160
+ background-color: var(--calendar-weekly-date-background-color, var(--md-sys-color-surface-container-lowest));
161
+ }
162
+
163
+ /*
164
+ What the host says is true of the day itself — the same channel and ordering rule as the
165
+ month view, which carries the reasoning.
166
+
167
+ Both of a day's cells take it here, the date band as well as the events under it, so a
168
+ non-working day reads as a whole column rather than a tinted strip with an untouched body.
169
+ */
170
+ li[date][day-state] {
171
+ background-color: var(--day-state-color);
100
172
  }
101
173
 
102
- li[selected] {
174
+ li[date][selected] {
103
175
  background-color: var(--calendar-weekly-selected-background-color, var(--md-sys-color-tertiary-container));
104
176
  color: var(--calendar-weekly-selected-color, var(--md-sys-color-on-tertiary-container));
105
177
  }
106
178
 
179
+ /*
180
+ Today, on the day rather than only inside it — the same token and the same reasoning as the
181
+ month view, which explains the gradient and the measured 10%.
182
+
183
+ No ring here, though. A day in this view is a whole column, two cells tall, and an inset ring
184
+ on each of them would draw a doubled rule across the middle where they meet. The column is
185
+ also large enough that the tint alone is found immediately — the month view needs the ring
186
+ because its cell is one of thirty-five.
187
+ */
188
+ li[today] {
189
+ background-image: linear-gradient(
190
+ var(--calendar-today-wash, color-mix(in srgb, var(--md-sys-color-primary, #262e38) 10%, transparent)),
191
+ var(--calendar-today-wash, color-mix(in srgb, var(--md-sys-color-primary, #262e38) 10%, transparent))
192
+ );
193
+ }
194
+
107
195
  span[date-label] {
108
196
  display: block;
109
197
  margin: var(--calendar-weekly-date-label-margin);
110
198
  text-align: var(--calendar-weekly-label-align, center);
199
+ /*
200
+ A column header, not content. It stood at the body's size and ink, so the row of dates
201
+ read as another row of data rather than as the heading of its column.
202
+ */
203
+ font-size: var(--md-sys-typescale-label-large-size, 0.8125rem);
204
+ font-weight: 500;
205
+ color: var(--md-sys-color-on-surface-variant);
111
206
  }
112
207
 
208
+ /*
209
+ The date, emphasised - not a filled pill.
210
+
211
+ Two rules used to sit here, one setting a weight and the next overriding it with a lozenge.
212
+
213
+ It was a solid lozenge in primary with reversed text. That made two maximum-contrast marks in
214
+ one cell once the cell itself took the ring, and this theme's primary is near-black, so in
215
+ light mode the lozenge read as an ink blot rather than an accent. It also made today's label
216
+ 39px wide where every other day's is 114px, so the number's left edge moved on one day of the
217
+ month - and in the week view it wrapped the weekday too, at 61px.
218
+
219
+ Weight carries it, and only weight. Tinting it as well pointed the emphasis two ways: primary
220
+ is a step away from the body ink, so a bolder today number came out measurably paler than
221
+ every ordinary day beside it — dE00 7.2 dark, 5.7 light, against cell contrast 9.94 where its
222
+ neighbours had 12.97. The ring is the accent-coloured thing; the number is a number.
223
+
224
+ The colour token stays, defaulting to the ink the cell already gives, for a host whose accent
225
+ is far enough from its body ink for a tint to add something.
226
+ */
113
227
  li[today] > span[date-label] {
114
- display: inline-block;
115
- background-color: var(--calendar-weekly-date-label-background-color, var(--md-sys-color-error, #cc3300));
116
- padding: var(--calendar-weekly-date-label-padding);
117
- border-radius: var(--calendar-weekly-date-label-border-radius, 999em);
118
- color: var(--calendar-weekly-date-label-color, var(--md-sys-color-on-error, #fff));
119
- min-width: 16px;
120
- text-align: center;
228
+ font-weight: 700;
229
+ color: var(--calendar-weekly-date-label-color, inherit);
230
+ }
231
+
232
+ li[date] {
233
+ max-height: var(--calendar-weekly-date-max-height, none);
234
+ /* The clip goes on the box that carries the ceiling — see the month view. */
235
+ overflow: hidden;
121
236
  }
122
237
 
123
238
  [date] div {
124
239
  display: block;
125
240
  /* Was the small keyword. */
126
241
  font-size: var(--md-sys-typescale-body-small-size, 0.75rem);
242
+ /*
243
+ Events ran into the cell's own borders — measured 0px on the left and 1px on the right,
244
+ while the date number above them sat 4px in. One cell, two left edges, and the titles
245
+ touching the rules on both sides.
246
+
247
+ The inset reads the date label's own margin, so the two lines stay together.
248
+ */
249
+ padding-inline: var(--calendar-weekly-date-label-margin, 4px);
127
250
  }
128
251
 
129
252
  [event] {
@@ -1 +1 @@
1
- {"version":3,"file":"calendar-weekly-styles.js","sourceRoot":"","sources":["../../src/calendar-weekly-styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAEzB,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0ItC,CAAA","sourcesContent":["import { css } from 'lit'\n\nexport const CalendarWeeklyStyles = css`\n :host {\n display: flex;\n flex-direction: column;\n color: var(--calendar-weekly-text-color, var(--md-sys-color-on-surface-variant, #585858));\n\n --md-text-button-container-height: 24px;\n }\n\n [head] {\n display: flex;\n align-items: center;\n }\n\n [head-week] {\n display: flex;\n /* left is not a value align-items accepts — the rule did nothing. */\n align-items: flex-start;\n }\n\n [this-week] {\n /* Was the x-large keyword, which is a browser step, not a step of this theme. */\n font-size: var(--md-sys-typescale-headline-small-size, 1.5rem);\n }\n\n [nav] {\n margin-left: auto;\n }\n\n /*\n * Same token the monthly view uses for its slotted switch.\n *\n * This used to override --md-sys-color-primary inside the component with\n * rgba(var(--secondary-color-rgb), 0.8), which never produced a color:\n *\n * host does not define --secondary-color-rgb the token resolves to empty, so nothing\n * reading it gets a color at all\n * host defines it as \"12 34 56\" rgba(12 34 56, 0.8) mixes space-separated\n * channels into the comma syntax — invalid,\n * and the property falls back to black\n *\n * [확인함] 2026-09-07 · both cases measured in a browser\n */\n ::slotted(*) {\n color: var(--md-sys-color-secondary);\n }\n\n ol {\n flex: 1;\n\n display: grid;\n grid-template-columns: repeat(7, 1fr);\n grid-template-rows: max-content;\n\n padding: 0;\n margin: var(--calendar-weekly-ol-margin, 9px 0);\n border-top: var(--calendar-weekly-ol-top-border, 3px solid var(--md-sys-color-outline, #999));\n }\n\n /*\n * The seven tracks are 1fr, and 1fr's minimum is min-content — so a cell whose chip is\n * white-space: nowrap pushes its own track wide and squeezes the rest.\n *\n * Measured at 700px with one long title: li widths came out\n * [58, 58, 353, 58, 58, 58, 58] without min-width: 0\n * [100 × 7] with it\n *\n * The host page had already asked for text-overflow: ellipsis on that chip, and it never\n * ran: the track grew instead of the text being clipped. [확인함] 2026-09-07\n */\n li {\n position: relative;\n min-width: 0;\n\n list-style: none;\n border: var(--calendar-weekly-border, 1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.1)));\n border-width: var(--calendar-weekly-border-width, 0 1px 1px 0px);\n opacity: var(--calendar-weekly-opacity);\n\n user-select: none;\n touch-action: none;\n }\n\n li:nth-child(7n + 1) {\n border-left-width: 1px;\n }\n\n li[day-of-week] {\n opacity: 1;\n background-color: var(--calendar-current-week-background-color, var(--md-sys-color-surface-variant));\n color: var(--calendar-current-week-color, var(--md-sys-color-on-surface));\n padding: var(--calendar-weekly-label-padding);\n text-align: center;\n }\n\n li[current-week] {\n background-color: var(--calendar-current-week-background-color, var(--md-sys-color-surface, #fff));\n opacity: 1;\n }\n\n li[selected] {\n background-color: var(--calendar-weekly-selected-background-color, var(--md-sys-color-tertiary-container));\n color: var(--calendar-weekly-selected-color, var(--md-sys-color-on-tertiary-container));\n }\n\n span[date-label] {\n display: block;\n margin: var(--calendar-weekly-date-label-margin);\n text-align: var(--calendar-weekly-label-align, center);\n }\n\n li[today] > span[date-label] {\n display: inline-block;\n background-color: var(--calendar-weekly-date-label-background-color, var(--md-sys-color-error, #cc3300));\n padding: var(--calendar-weekly-date-label-padding);\n border-radius: var(--calendar-weekly-date-label-border-radius, 999em);\n color: var(--calendar-weekly-date-label-color, var(--md-sys-color-on-error, #fff));\n min-width: 16px;\n text-align: center;\n }\n\n [date] div {\n display: block;\n /* Was the small keyword. */\n font-size: var(--md-sys-typescale-body-small-size, 0.75rem);\n }\n\n [event] {\n display: block;\n background-color: var(--calendar-weekly-background-color);\n border: var(--calendar-weekly-event-border);\n border-width: var(--calendar-weekly-event-border-width);\n margin: var(--calendar-weekly-event-margin, 0 0 4px 0);\n padding: var(--calendar-weekly-event-padding, 2px 4px 2px 4px);\n\n user-select: all;\n touch-action: all;\n }\n`\n"]}
1
+ {"version":3,"file":"calendar-weekly-styles.js","sourceRoot":"","sources":["../../src/calendar-weekly-styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAEzB,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqQtC,CAAA","sourcesContent":["import { css } from 'lit'\n\nexport const CalendarWeeklyStyles = css`\n :host {\n display: flex;\n flex-direction: column;\n color: var(--calendar-weekly-text-color, var(--md-sys-color-on-surface-variant, #585858));\n\n /*\n One row of controls, one height. The text button was pinned to 24px while the icon\n buttons beside it are 40, so the middle of the three sat in a different band.\n */\n --md-text-button-container-height: 32px;\n --md-icon-button-icon-size: 20px;\n --md-icon-button-state-layer-height: 32px;\n --md-icon-button-state-layer-width: 32px;\n }\n\n [head] {\n display: flex;\n align-items: center;\n /*\n The view switch sat flush against the next button — measured 0px between them.\n\n The space goes on the switch, not on the row: a flex gap also opens a gap between the\n title and the nav, and those two extra pixels each made the header 8px wider than the\n grid under it, which put a horizontal scrollbar on the whole calendar. [확인함] 2026-09-11\n */\n }\n\n [head-week] {\n display: flex;\n /* left is not a value align-items accepts — the rule did nothing. */\n align-items: flex-start;\n }\n\n [this-week] {\n /* Was the x-large keyword, which is a browser step, not a step of this theme. */\n font-size: var(--md-sys-typescale-headline-small-size, 1.5rem);\n /*\n The month used to be wrapped in <b>. Formatting the whole title through Intl dropped\n that tag and left 24px at weight 400 — large, but with nothing to say it is the title.\n */\n font-weight: var(--md-sys-typescale-headline-small-weight, 640);\n /*\n The header must never be what makes the calendar scroll sideways. A flex item's floor is\n its content, so without this the title pushes the nav out and the grid follows — the same\n rule the day cells needed.\n */\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n [nav] {\n margin-left: auto;\n }\n\n /*\n Room for what the buttons actually occupy.\n\n An md-icon-button paints a 48px touch target around its 32px box, so the rightmost control\n reaches 8px past its own edge. With that control flush to the header's right edge the\n header measured 8px wider than the grid under it, and the whole calendar grew a horizontal\n scrollbar. [확인함] 2026-09-11 — button right 898, its inner target 906, header client 860.\n\n The inset makes room instead of shrinking the target: a smaller target is a worse button,\n and the last control here is slotted by the host, whose size this component cannot know.\n */\n [head] {\n padding-right: var(--calendar-head-inset, 8px);\n }\n\n /*\n * Same token the monthly view uses for its slotted switch.\n *\n * This used to override --md-sys-color-primary inside the component with\n * rgba(var(--secondary-color-rgb), 0.8), which never produced a color:\n *\n * host does not define --secondary-color-rgb the token resolves to empty, so nothing\n * reading it gets a color at all\n * host defines it as \"12 34 56\" rgba(12 34 56, 0.8) mixes space-separated\n * channels into the comma syntax — invalid,\n * and the property falls back to black\n *\n * [확인함] 2026-09-07 · both cases measured in a browser\n */\n ::slotted(*) {\n color: var(--md-sys-color-secondary);\n }\n\n ol {\n flex: 1;\n\n display: grid;\n grid-template-columns: repeat(7, 1fr);\n grid-template-rows: max-content;\n\n padding: 0;\n margin: var(--calendar-weekly-ol-margin, 9px 0);\n border-top: var(--calendar-weekly-ol-top-border, 3px solid var(--md-sys-color-outline, #999));\n /* Same as the month view — the grid is one box and closes its own corners. */\n border-radius: var(--calendar-weekly-radius, var(--ui-r-small, 6px));\n overflow: hidden;\n }\n\n /*\n * The seven tracks are 1fr, and 1fr's minimum is min-content — so a cell whose chip is\n * white-space: nowrap pushes its own track wide and squeezes the rest.\n *\n * Measured at 700px with one long title: li widths came out\n * [58, 58, 353, 58, 58, 58, 58] without min-width: 0\n * [100 × 7] with it\n *\n * The host page had already asked for text-overflow: ellipsis on that chip, and it never\n * ran: the track grew instead of the text being clipped. [확인함] 2026-09-07\n */\n li {\n position: relative;\n min-width: 0;\n\n list-style: none;\n border: var(--calendar-weekly-border, 1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.1)));\n border-width: var(--calendar-weekly-border-width, 0 1px 1px 0px);\n opacity: var(--calendar-weekly-opacity);\n\n user-select: none;\n touch-action: none;\n }\n\n li:nth-child(7n + 1) {\n border-left-width: 1px;\n }\n\n li[day-of-week] {\n opacity: 1;\n background-color: var(--calendar-current-week-background-color, var(--md-sys-color-surface));\n color: var(--calendar-current-week-color, var(--md-sys-color-on-surface));\n padding: var(--calendar-weekly-label-padding);\n text-align: center;\n }\n\n /*\n The cells that hold the events.\n\n They carried no surface at all. This view draws two rows of seven - the dates on top, the\n events under them - and only the date row was painted, by the rule above. The event row was\n transparent, so it showed whatever the host put behind the calendar, which on the plant page\n is the same colour as the date band. [확인함] 2026-09-11 — both measured rgb(240,242,244),\n and the outer box behind them the same again.\n\n So the week view never got the separation the month view has: there, the days you are\n reading are the brightest surface and the band above them is a step down. Same ladder here.\n\n A rule for li[current-week] used to sit in this place. Nothing has ever carried that\n attribute - the markup writes day-of-week on the date row and nothing on this one - so it\n painted nothing, while reading the token that the date band above actually uses.\n */\n li[date]:not([day-of-week]) {\n background-color: var(--calendar-weekly-date-background-color, var(--md-sys-color-surface-container-lowest));\n }\n\n /*\n What the host says is true of the day itself — the same channel and ordering rule as the\n month view, which carries the reasoning.\n\n Both of a day's cells take it here, the date band as well as the events under it, so a\n non-working day reads as a whole column rather than a tinted strip with an untouched body.\n */\n li[date][day-state] {\n background-color: var(--day-state-color);\n }\n\n li[date][selected] {\n background-color: var(--calendar-weekly-selected-background-color, var(--md-sys-color-tertiary-container));\n color: var(--calendar-weekly-selected-color, var(--md-sys-color-on-tertiary-container));\n }\n\n /*\n Today, on the day rather than only inside it — the same token and the same reasoning as the\n month view, which explains the gradient and the measured 10%.\n\n No ring here, though. A day in this view is a whole column, two cells tall, and an inset ring\n on each of them would draw a doubled rule across the middle where they meet. The column is\n also large enough that the tint alone is found immediately — the month view needs the ring\n because its cell is one of thirty-five.\n */\n li[today] {\n background-image: linear-gradient(\n var(--calendar-today-wash, color-mix(in srgb, var(--md-sys-color-primary, #262e38) 10%, transparent)),\n var(--calendar-today-wash, color-mix(in srgb, var(--md-sys-color-primary, #262e38) 10%, transparent))\n );\n }\n\n span[date-label] {\n display: block;\n margin: var(--calendar-weekly-date-label-margin);\n text-align: var(--calendar-weekly-label-align, center);\n /*\n A column header, not content. It stood at the body's size and ink, so the row of dates\n read as another row of data rather than as the heading of its column.\n */\n font-size: var(--md-sys-typescale-label-large-size, 0.8125rem);\n font-weight: 500;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n /*\n The date, emphasised - not a filled pill.\n\n Two rules used to sit here, one setting a weight and the next overriding it with a lozenge.\n\n It was a solid lozenge in primary with reversed text. That made two maximum-contrast marks in\n one cell once the cell itself took the ring, and this theme's primary is near-black, so in\n light mode the lozenge read as an ink blot rather than an accent. It also made today's label\n 39px wide where every other day's is 114px, so the number's left edge moved on one day of the\n month - and in the week view it wrapped the weekday too, at 61px.\n\n Weight carries it, and only weight. Tinting it as well pointed the emphasis two ways: primary\n is a step away from the body ink, so a bolder today number came out measurably paler than\n every ordinary day beside it — dE00 7.2 dark, 5.7 light, against cell contrast 9.94 where its\n neighbours had 12.97. The ring is the accent-coloured thing; the number is a number.\n\n The colour token stays, defaulting to the ink the cell already gives, for a host whose accent\n is far enough from its body ink for a tint to add something.\n */\n li[today] > span[date-label] {\n font-weight: 700;\n color: var(--calendar-weekly-date-label-color, inherit);\n }\n\n li[date] {\n max-height: var(--calendar-weekly-date-max-height, none);\n /* The clip goes on the box that carries the ceiling — see the month view. */\n overflow: hidden;\n }\n\n [date] div {\n display: block;\n /* Was the small keyword. */\n font-size: var(--md-sys-typescale-body-small-size, 0.75rem);\n /*\n Events ran into the cell's own borders — measured 0px on the left and 1px on the right,\n while the date number above them sat 4px in. One cell, two left edges, and the titles\n touching the rules on both sides.\n\n The inset reads the date label's own margin, so the two lines stay together.\n */\n padding-inline: var(--calendar-weekly-date-label-margin, 4px);\n }\n\n [event] {\n display: block;\n background-color: var(--calendar-weekly-background-color);\n border: var(--calendar-weekly-event-border);\n border-width: var(--calendar-weekly-event-border-width);\n margin: var(--calendar-weekly-event-margin, 0 0 4px 0);\n padding: var(--calendar-weekly-event-padding, 2px 4px 2px 4px);\n\n user-select: all;\n touch-action: all;\n }\n`\n"]}
@@ -1,7 +1,9 @@
1
1
  import '@material/web/button/text-button.js';
2
+ import '@material/web/iconbutton/icon-button.js';
3
+ import '@material/web/icon/icon.js';
2
4
  import { Dayjs } from 'dayjs/esm/index.js';
3
5
  import { LitElement, PropertyValues } from 'lit';
4
- import { BizEvent, CALENDAR, EventProvider } from './types.js';
6
+ import { BizEvent, CALENDAR, DayState, EventProvider } from './types.js';
5
7
  export declare class CalendarWeekly extends LitElement {
6
8
  static styles: import("lit").CSSResult[];
7
9
  eventProvider?: EventProvider;
@@ -10,8 +12,13 @@ export declare class CalendarWeekly extends LitElement {
10
12
  week: number;
11
13
  calendar?: CALENDAR;
12
14
  eventMap?: Map<Date, BizEvent[]>;
15
+ /** What is true of the days themselves, if the host answers for them. See {@link DayState}. */
16
+ dayStateMap?: Map<Date, DayState>;
13
17
  selections?: [Date, Date];
14
18
  pointerDownDate?: Date | null;
19
+ /** Last reported overflow, so the host is not told the same thing after every render. */
20
+ private lastOverflow;
21
+ private tooltip;
15
22
  render(): import("lit-html").TemplateResult<1>;
16
23
  updated(changes: PropertyValues<this>): Promise<void>;
17
24
  moveTo(year: number, month: number, week: number): void;
@@ -1,48 +1,89 @@
1
1
  import { __decorate } from "tslib";
2
2
  import '@material/web/button/text-button.js';
3
+ import '@material/web/iconbutton/icon-button.js';
4
+ import '@material/web/icon/icon.js';
3
5
  import dayjs from 'dayjs/esm/index.js';
4
6
  import { html, LitElement } from 'lit';
5
7
  import { customElement, property, state } from 'lit/decorators.js';
8
+ import { ifDefined } from 'lit/directives/if-defined.js';
9
+ import { TooltipReactiveController } from '@operato/utils';
6
10
  import { CalendarWeeklyStyles } from './calendar-weekly-styles.js';
7
- import { WEEKDAYS, isToday } from './types.js';
11
+ import { reportDayOverflow } from './day-overflow.js';
12
+ import { isToday, dayLabel, monthTitle, nextWeekLabel, previousWeekLabel, todayLabel, weekdayNames } from './types.js';
8
13
  let CalendarWeekly = class CalendarWeekly extends LitElement {
9
14
  constructor() {
10
15
  super(...arguments);
11
16
  this.year = dayjs().year();
12
17
  this.month = dayjs().month();
13
18
  this.week = dayjs().week();
19
+ /** Last reported overflow, so the host is not told the same thing after every render. */
20
+ this.lastOverflow = '';
21
+ /*
22
+ * Event titles are drawn on one nowrap line and cut with an ellipsis, so the full name only
23
+ * exists in a tooltip. Hosts were reaching for the browser's own `title`, which waits about a
24
+ * second and cannot be styled — measured on the plant calendar.
25
+ *
26
+ * data-grist already runs this controller on its header and its cells. It waits 450ms so a
27
+ * pointer crossing the grid does not trail tooltips behind it, then drops the wait once one
28
+ * is up, and it only fires on elements that actually overflow — which is exactly the set of
29
+ * titles worth expanding.
30
+ *
31
+ * Hosts mark the rows they want expanded with data-reactive-tooltip. The listener sits on
32
+ * this shadow root, where the host's own event templates are rendered.
33
+ */
34
+ this.tooltip = new TooltipReactiveController(this, {
35
+ /*
36
+ * Read the attribute's value, not the row's text.
37
+ *
38
+ * The controller treats the attribute as a marker and otherwise repeats what is already on
39
+ * screen, which for a cut title is at least the whole title. But a host writes the line it
40
+ * wants read - the plant calendar puts the kind, the order and where it runs in there - and
41
+ * without this that sentence was thrown away. [확인함] 2026-09-11
42
+ */
43
+ content: element => element.getAttribute('data-reactive-tooltip') || element.textContent?.trim() || ''
44
+ });
14
45
  }
15
46
  static { this.styles = [CalendarWeeklyStyles]; }
16
47
  render() {
17
48
  return html `
18
49
  <div head>
19
50
  <div this-week>
20
- <b>${dayjs(new Date(this.year, this.month)).format('MMMM')}</b> ${this.year} <b>Week ${this.week}</b>
51
+ <!--
52
+ W37 is the ISO 8601 week designator. The word "Week" was English on every screen,
53
+ and Intl has no name for a week number, so the marker carries it instead of a word.
54
+ -->
55
+ ${monthTitle(this.year, this.month)} · W${this.week}
21
56
  </div>
22
57
 
23
58
  <div nav>
24
- <md-text-button
59
+ <md-icon-button
60
+ aria-label=${previousWeekLabel()}
61
+ title=${previousWeekLabel()}
25
62
  @click=${() => {
26
63
  const dayJs = this.getLastDateOfWeek(this.year, this.week);
27
64
  const prevWeek = dayJs.subtract(1, 'week');
28
65
  this.moveTo(prevWeek.year(), prevWeek.month(), prevWeek.week());
29
66
  }}
30
- ><</md-text-button
31
67
  >
68
+ <md-icon>chevron_left</md-icon>
69
+ </md-icon-button>
32
70
  <md-text-button
33
71
  @click=${() => {
34
72
  this.moveTo(dayjs().year(), dayjs().month(), dayjs().week());
35
73
  }}
36
- >Today</md-text-button
74
+ >${todayLabel()}</md-text-button
37
75
  >
38
- <md-text-button
76
+ <md-icon-button
77
+ aria-label=${nextWeekLabel()}
78
+ title=${nextWeekLabel()}
39
79
  @click=${() => {
40
80
  const dayJs = this.getLastDateOfWeek(this.year, this.week);
41
81
  const nextWeek = dayJs.add(1, 'week');
42
82
  this.moveTo(nextWeek.year(), nextWeek.month(), nextWeek.week());
43
83
  }}
44
- >></md-text-button
45
84
  >
85
+ <md-icon>chevron_right</md-icon>
86
+ </md-icon-button>
46
87
  </div>
47
88
 
48
89
  <slot></slot>
@@ -58,8 +99,17 @@ let CalendarWeekly = class CalendarWeekly extends LitElement {
58
99
  const { date: thisDate } = date;
59
100
  const selected = from && to && thisDate >= from && thisDate <= to;
60
101
  return html `
61
- <li ?today=${date.today} day-of-week date .date=${thisDate} ?selected=${selected}>
62
- <span date-label>${date.label}(${WEEKDAYS[index]})</span>
102
+ <li
103
+ ?today=${date.today}
104
+ day-of-week
105
+ date
106
+ day-state=${ifDefined(this.dayStateMap?.get(thisDate)?.name)}
107
+ style=${ifDefined(this.dayStateMap?.get(thisDate) &&
108
+ `--day-state-color:${this.dayStateMap.get(thisDate).color}`)}
109
+ .date=${thisDate}
110
+ ?selected=${selected}
111
+ >
112
+ <span date-label>${dayLabel(date.date, !!date.withMonth)} (${weekdayNames()[index]})</span>
63
113
  </li>
64
114
  `;
65
115
  })}
@@ -67,7 +117,22 @@ let CalendarWeekly = class CalendarWeekly extends LitElement {
67
117
  const [from, to] = this.selections || [];
68
118
  const { date: thisDate } = date;
69
119
  const selected = from && to && thisDate >= from && thisDate <= to;
70
- return html `<li date .date=${thisDate} ?selected=${selected}>
120
+ /*
121
+ * The event cell carries today as well as the date cell above it.
122
+ *
123
+ * This view draws a day as two cells in one column - the date on top, its events
124
+ * under it - and only the top one was marked. Today's tint therefore stopped at the
125
+ * date band, which is the part you are least likely to be looking at.
126
+ */
127
+ const dayState = this.dayStateMap?.get(thisDate);
128
+ return html `<li
129
+ date
130
+ ?today=${date.today}
131
+ day-state=${ifDefined(dayState?.name)}
132
+ style=${ifDefined(dayState && `--day-state-color:${dayState.color}`)}
133
+ .date=${thisDate}
134
+ ?selected=${selected}
135
+ >
71
136
  <div>
72
137
  ${(this.eventMap?.get(date?.date) || []).map(({ title, color, template }) => template ? template : html `<span event style="border-color: ${color};">${title}</span>`)}
73
138
  </div>
@@ -79,9 +144,21 @@ let CalendarWeekly = class CalendarWeekly extends LitElement {
79
144
  async updated(changes) {
80
145
  if (changes.has('year') || changes.has('month') || changes.has('week') || changes.has('eventProvider')) {
81
146
  const calendar = this.createDaysForCurrentWeek(this.year, this.week);
82
- this.eventMap = await this.eventProvider?.fetchEventsForCalendar(calendar);
147
+ /* Both questions go out together — see the month view for why. */
148
+ const [eventMap, dayStateMap] = await Promise.all([
149
+ this.eventProvider?.fetchEventsForCalendar(calendar),
150
+ this.eventProvider?.fetchDayStatesForCalendar?.(calendar)
151
+ ]);
152
+ this.eventMap = eventMap;
153
+ this.dayStateMap = dayStateMap;
83
154
  this.calendar = calendar;
84
155
  }
156
+ /*
157
+ * After the rows are laid out, not before. A cap only bites once the browser has placed the
158
+ * children, so this has to run on every render - the grid also reflows when the host swaps
159
+ * its templates or the window changes width.
160
+ */
161
+ this.lastOverflow = reportDayOverflow(this, this.shadowRoot, this.lastOverflow);
85
162
  }
86
163
  moveTo(year, month, week) {
87
164
  this.year = year;
@@ -160,7 +237,7 @@ let CalendarWeekly = class CalendarWeekly extends LitElement {
160
237
  return [...Array(weekDays)]
161
238
  .map((day, index) => {
162
239
  const date = new Date(lastDayjs.year(), lastDayjs.month(), lastDayjs.date() - index);
163
- const label = dayjs(date).format('MM-DD');
240
+ const label = dayLabel(date, true);
164
241
  return {
165
242
  date,
166
243
  label,
@@ -189,6 +266,9 @@ __decorate([
189
266
  __decorate([
190
267
  state()
191
268
  ], CalendarWeekly.prototype, "eventMap", void 0);
269
+ __decorate([
270
+ state()
271
+ ], CalendarWeekly.prototype, "dayStateMap", void 0);
192
272
  __decorate([
193
273
  state()
194
274
  ], CalendarWeekly.prototype, "selections", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"calendar-weekly.js","sourceRoot":"","sources":["../../src/calendar-weekly.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/text-button.js'\n\nimport dayjs, { Dayjs } from 'dayjs/esm/index.js'\nimport { html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { CalendarWeeklyStyles } from './calendar-weekly-styles.js'\nimport { BizEvent, CALENDAR, WEEKDAYS, EventProvider, isToday } from './types.js'\n\n@customElement('calendar-weekly')\nexport class CalendarWeekly extends LitElement {\n static styles = [CalendarWeeklyStyles]\n\n @property({ type: Object }) eventProvider?: EventProvider\n\n @state() year: number = dayjs().year()\n @state() month: number = dayjs().month()\n @state() week: number = dayjs().week()\n @state() calendar?: CALENDAR\n @state() eventMap?: Map<Date, BizEvent[]>\n @state() selections?: [Date, Date]\n\n @state() pointerDownDate?: Date | null\n\n render() {\n return html`\n <div head>\n <div this-week>\n <b>${dayjs(new Date(this.year, this.month)).format('MMMM')}</b> ${this.year} <b>Week ${this.week}</b>\n </div>\n\n <div nav>\n <md-text-button\n @click=${() => {\n const dayJs = this.getLastDateOfWeek(this.year, this.week)\n const prevWeek = dayJs.subtract(1, 'week')\n this.moveTo(prevWeek.year(), prevWeek.month(), prevWeek.week())\n }}\n ><</md-text-button\n >\n <md-text-button\n @click=${() => {\n this.moveTo(dayjs().year(), dayjs().month(), dayjs().week())\n }}\n >Today</md-text-button\n >\n <md-text-button\n @click=${() => {\n const dayJs = this.getLastDateOfWeek(this.year, this.week)\n const nextWeek = dayJs.add(1, 'week')\n this.moveTo(nextWeek.year(), nextWeek.month(), nextWeek.week())\n }}\n >></md-text-button\n >\n </div>\n\n <slot></slot>\n </div>\n\n <ol\n @pointerdown=${this.handlePointerDown}\n @pointermove=${this.handlePointerMove}\n @pointerup=${this.handlePointerUp}\n >\n ${this.calendar?.map((date, index) => {\n const [from, to] = this.selections || ([] as any)\n const { date: thisDate } = date\n const selected = from && to && thisDate >= from && thisDate <= to\n\n return html`\n <li ?today=${date.today} day-of-week date .date=${thisDate} ?selected=${selected}>\n <span date-label>${date.label}(${WEEKDAYS[index]})</span>\n </li>\n `\n })}\n ${this.calendar?.map(date => {\n const [from, to] = this.selections || ([] as any)\n const { date: thisDate } = date\n const selected = from && to && thisDate >= from && thisDate <= to\n\n return html`<li date .date=${thisDate} ?selected=${selected}>\n <div>\n ${(this.eventMap?.get(date?.date) || []).map(({ title, color, template }) =>\n template ? template : html`<span event style=\"border-color: ${color};\">${title}</span>`\n )}\n </div>\n </li>`\n })}\n </ol>\n `\n }\n\n async updated(changes: PropertyValues<this>) {\n if (changes.has('year') || changes.has('month') || changes.has('week') || changes.has('eventProvider')) {\n const calendar = this.createDaysForCurrentWeek(this.year, this.week)\n\n this.eventMap = await this.eventProvider?.fetchEventsForCalendar(calendar)\n this.calendar = calendar\n }\n }\n\n moveTo(year: number, month: number, week: number) {\n this.year = year\n this.month = month\n this.week = week\n }\n\n handlePointerDown(event: PointerEvent) {\n const target = event.target as HTMLElement\n\n if (!target.hasAttribute('date') && !target.hasAttribute('date-label')) {\n return\n }\n\n const dateElement = target.closest('[date]') as HTMLElement\n const from = (dateElement as any).date\n\n this.pointerDownDate = from\n\n // 캡처를 설정하지 않음(Touch 디바이스에서 중요)\n target.releasePointerCapture(event.pointerId)\n\n event.preventDefault()\n }\n\n handlePointerMove(event: PointerEvent) {\n const from = this.pointerDownDate\n\n if (!from) {\n return\n }\n\n const target = event.target as HTMLElement\n const dateElement = target.closest('[date]') as HTMLElement\n\n if (!dateElement) {\n return\n }\n\n const date = (dateElement as any).date\n this.selections = from > date ? [date, from] : [from, date]\n\n // 캡처를 설정하지 않음(Touch 디바이스에서 중요)\n target.releasePointerCapture(event.pointerId)\n\n event.preventDefault()\n }\n\n handlePointerUp(event: PointerEvent) {\n const from = this.pointerDownDate\n\n this.pointerDownDate = null\n\n if (!from) {\n return\n }\n\n const target = event.target as HTMLElement\n const dateElement = target.closest('[date]') as HTMLElement\n\n if (!dateElement) {\n return\n }\n\n const date = (dateElement as any).date\n this.selections = from > date ? [date, from] : [from, date]\n\n this.dispatchEvent(\n new CustomEvent('select-date', {\n detail: this.selections,\n bubbles: true,\n composed: true\n })\n )\n\n event.preventDefault()\n }\n\n selectDate(date: { label: string; date: Date; thisMonth?: boolean; thisWeek?: boolean; today?: boolean }) {\n if (date) {\n this.selections = [date.date, date.date]\n } else {\n this.selections = undefined\n }\n\n this.dispatchEvent(\n new CustomEvent('select-date', {\n detail: date,\n bubbles: true,\n composed: true\n })\n )\n }\n\n getLastDateOfWeek(year: number, week: number): Dayjs {\n const firstWeekLastDay = dayjs(new Date(year, 0, 1)).endOf('w')\n week -= 1 // one-based week, so need the minus-one\n return firstWeekLastDay.add(week, 'w')\n }\n\n createDaysForCurrentWeek(year: number, week: number): CALENDAR {\n const lastDayjs = this.getLastDateOfWeek(year, week)\n const weekDays = 7\n\n return [...Array(weekDays)]\n .map((day, index) => {\n const date = new Date(lastDayjs.year(), lastDayjs.month(), lastDayjs.date() - index)\n const label = dayjs(date).format('MM-DD')\n return {\n date,\n label,\n thisWeek: true,\n today: isToday(date)\n }\n })\n .reverse()\n }\n}\n"]}
1
+ {"version":3,"file":"calendar-weekly.js","sourceRoot":"","sources":["../../src/calendar-weekly.ts"],"names":[],"mappings":";AAAA,OAAO,qCAAqC,CAAA;AAC5C,OAAO,yCAAyC,CAAA;AAChD,OAAO,4BAA4B,CAAA;AAEnC,OAAO,KAAgB,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAkB,MAAM,KAAK,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAExD,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAA;AAE1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAKL,OAAO,EACP,QAAQ,EACR,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,YAAY,EACb,MAAM,YAAY,CAAA;AAGZ,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,UAAU;IAAvC;;QAKI,SAAI,GAAW,KAAK,EAAE,CAAC,IAAI,EAAE,CAAA;QAC7B,UAAK,GAAW,KAAK,EAAE,CAAC,KAAK,EAAE,CAAA;QAC/B,SAAI,GAAW,KAAK,EAAE,CAAC,IAAI,EAAE,CAAA;QAStC,yFAAyF;QACjF,iBAAY,GAAG,EAAE,CAAA;QAEzB;;;;;;;;;;;;WAYG;QACK,YAAO,GAAG,IAAI,yBAAyB,CAAC,IAAI,EAAE;YACpD;;;;;;;eAOG;YACH,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,uBAAuB,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE;SACvG,CAAC,CAAA;IAsPJ,CAAC;aA/RQ,WAAM,GAAG,CAAC,oBAAoB,CAAC,AAAzB,CAAyB;IA2CtC,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;;;YAOH,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,IAAI;;;;;yBAKpC,iBAAiB,EAAE;oBACxB,iBAAiB,EAAE;qBAClB,GAAG,EAAE;YACZ,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;YAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;YAC1C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,QAAQ,CAAC,KAAK,EAAE,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;QACjE,CAAC;;;;;qBAKQ,GAAG,EAAE;YACZ,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,CAAA;QAC9D,CAAC;eACE,UAAU,EAAE;;;yBAGF,aAAa,EAAE;oBACpB,aAAa,EAAE;qBACd,GAAG,EAAE;YACZ,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;YAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;YACrC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,QAAQ,CAAC,KAAK,EAAE,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;QACjE,CAAC;;;;;;;;;;uBAUU,IAAI,CAAC,iBAAiB;uBACtB,IAAI,CAAC,iBAAiB;qBACxB,IAAI,CAAC,eAAe;;UAE/B,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YACnC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,IAAK,EAAU,CAAA;YACjD,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAA;YAC/B,MAAM,QAAQ,GAAG,IAAI,IAAI,EAAE,IAAI,QAAQ,IAAI,IAAI,IAAI,QAAQ,IAAI,EAAE,CAAA;YAEjE,OAAO,IAAI,CAAA;;uBAEE,IAAI,CAAC,KAAK;;;0BAGP,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC;sBACpD,SAAS,CACf,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,QAAQ,CAAC;gBAC7B,qBAAqB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC,KAAK,EAAE,CAC/D;sBACO,QAAQ;0BACJ,QAAQ;;iCAED,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,YAAY,EAAE,CAAC,KAAK,CAAC;;WAErF,CAAA;QACH,CAAC,CAAC;UACA,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE;YAC1B,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,IAAK,EAAU,CAAA;YACjD,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAA;YAC/B,MAAM,QAAQ,GAAG,IAAI,IAAI,EAAE,IAAI,QAAQ,IAAI,IAAI,IAAI,QAAQ,IAAI,EAAE,CAAA;YAEjE;;;;;;eAMG;YACH,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAA;YAEhD,OAAO,IAAI,CAAA;;qBAEA,IAAI,CAAC,KAAK;wBACP,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC;oBAC7B,SAAS,CAAC,QAAQ,IAAI,qBAAqB,QAAQ,CAAC,KAAK,EAAE,CAAC;oBAC5D,QAAQ;wBACJ,QAAQ;;;gBAGhB,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,CAC1E,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAA,oCAAoC,KAAK,MAAM,KAAK,SAAS,CACxF;;gBAEC,CAAA;QACR,CAAC,CAAC;;KAEL,CAAA;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAA6B;QACzC,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;YACvG,MAAM,QAAQ,GAAG,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;YAEpE,kEAAkE;YAClE,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBAChD,IAAI,CAAC,aAAa,EAAE,sBAAsB,CAAC,QAAQ,CAAC;gBACpD,IAAI,CAAC,aAAa,EAAE,yBAAyB,EAAE,CAAC,QAAQ,CAAC;aAC1D,CAAC,CAAA;YAEF,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;YACxB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAA;YAC9B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;QAC1B,CAAC;QAED;;;;WAIG;QACH,IAAI,CAAC,YAAY,GAAG,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,YAAY,CAAC,CAAA;IACjF,CAAC;IAED,MAAM,CAAC,IAAY,EAAE,KAAa,EAAE,IAAY;QAC9C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAClB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;IAED,iBAAiB,CAAC,KAAmB;QACnC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAqB,CAAA;QAE1C,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,CAAC;YACvE,OAAM;QACR,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAgB,CAAA;QAC3D,MAAM,IAAI,GAAI,WAAmB,CAAC,IAAI,CAAA;QAEtC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAA;QAE3B,+BAA+B;QAC/B,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;QAE7C,KAAK,CAAC,cAAc,EAAE,CAAA;IACxB,CAAC;IAED,iBAAiB,CAAC,KAAmB;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAA;QAEjC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAM;QACR,CAAC;QAED,MAAM,MAAM,GAAG,KAAK,CAAC,MAAqB,CAAA;QAC1C,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAgB,CAAA;QAE3D,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAM;QACR,CAAC;QAED,MAAM,IAAI,GAAI,WAAmB,CAAC,IAAI,CAAA;QACtC,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QAE3D,+BAA+B;QAC/B,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;QAE7C,KAAK,CAAC,cAAc,EAAE,CAAA;IACxB,CAAC;IAED,eAAe,CAAC,KAAmB;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAA;QAEjC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAA;QAE3B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAM;QACR,CAAC;QAED,MAAM,MAAM,GAAG,KAAK,CAAC,MAAqB,CAAA;QAC1C,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAgB,CAAA;QAE3D,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAM;QACR,CAAC;QAED,MAAM,IAAI,GAAI,WAAmB,CAAC,IAAI,CAAA;QACtC,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QAE3D,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,aAAa,EAAE;YAC7B,MAAM,EAAE,IAAI,CAAC,UAAU;YACvB,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAA;QAED,KAAK,CAAC,cAAc,EAAE,CAAA;IACxB,CAAC;IAED,UAAU,CAAC,IAA6F;QACtG,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QAC1C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,UAAU,GAAG,SAAS,CAAA;QAC7B,CAAC;QAED,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,aAAa,EAAE;YAC7B,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAA;IACH,CAAC;IAED,iBAAiB,CAAC,IAAY,EAAE,IAAY;QAC1C,MAAM,gBAAgB,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC/D,IAAI,IAAI,CAAC,CAAA,CAAC,wCAAwC;QAClD,OAAO,gBAAgB,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IACxC,CAAC;IAED,wBAAwB,CAAC,IAAY,EAAE,IAAY;QACjD,MAAM,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QACpD,MAAM,QAAQ,GAAG,CAAC,CAAA;QAElB,OAAO,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;aACxB,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YAClB,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,CAAA;YACpF,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;YAClC,OAAO;gBACL,IAAI;gBACJ,KAAK;gBACL,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC;aACrB,CAAA;QACH,CAAC,CAAC;aACD,OAAO,EAAE,CAAA;IACd,CAAC;;AA5R2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;qDAA8B;AAEhD;IAAR,KAAK,EAAE;4CAA8B;AAC7B;IAAR,KAAK,EAAE;6CAAgC;AAC/B;IAAR,KAAK,EAAE;4CAA8B;AAC7B;IAAR,KAAK,EAAE;gDAAoB;AACnB;IAAR,KAAK,EAAE;gDAAiC;AAEhC;IAAR,KAAK,EAAE;mDAAkC;AACjC;IAAR,KAAK,EAAE;kDAA0B;AAEzB;IAAR,KAAK,EAAE;uDAA8B;AAd3B,cAAc;IAD1B,aAAa,CAAC,iBAAiB,CAAC;GACpB,cAAc,CAgS1B","sourcesContent":["import '@material/web/button/text-button.js'\nimport '@material/web/iconbutton/icon-button.js'\nimport '@material/web/icon/icon.js'\n\nimport dayjs, { Dayjs } from 'dayjs/esm/index.js'\nimport { html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\nimport { TooltipReactiveController } from '@operato/utils'\n\nimport { CalendarWeeklyStyles } from './calendar-weekly-styles.js'\nimport { reportDayOverflow } from './day-overflow.js'\nimport {\n BizEvent,\n CALENDAR,\n DayState,\n EventProvider,\n isToday,\n dayLabel,\n monthTitle,\n nextWeekLabel,\n previousWeekLabel,\n todayLabel,\n weekdayNames\n} from './types.js'\n\n@customElement('calendar-weekly')\nexport class CalendarWeekly extends LitElement {\n static styles = [CalendarWeeklyStyles]\n\n @property({ type: Object }) eventProvider?: EventProvider\n\n @state() year: number = dayjs().year()\n @state() month: number = dayjs().month()\n @state() week: number = dayjs().week()\n @state() calendar?: CALENDAR\n @state() eventMap?: Map<Date, BizEvent[]>\n /** What is true of the days themselves, if the host answers for them. See {@link DayState}. */\n @state() dayStateMap?: Map<Date, DayState>\n @state() selections?: [Date, Date]\n\n @state() pointerDownDate?: Date | null\n\n /** Last reported overflow, so the host is not told the same thing after every render. */\n private lastOverflow = ''\n\n /*\n * Event titles are drawn on one nowrap line and cut with an ellipsis, so the full name only\n * exists in a tooltip. Hosts were reaching for the browser's own `title`, which waits about a\n * second and cannot be styled — measured on the plant calendar.\n *\n * data-grist already runs this controller on its header and its cells. It waits 450ms so a\n * pointer crossing the grid does not trail tooltips behind it, then drops the wait once one\n * is up, and it only fires on elements that actually overflow — which is exactly the set of\n * titles worth expanding.\n *\n * Hosts mark the rows they want expanded with data-reactive-tooltip. The listener sits on\n * this shadow root, where the host's own event templates are rendered.\n */\n private tooltip = new TooltipReactiveController(this, {\n /*\n * Read the attribute's value, not the row's text.\n *\n * The controller treats the attribute as a marker and otherwise repeats what is already on\n * screen, which for a cut title is at least the whole title. But a host writes the line it\n * wants read - the plant calendar puts the kind, the order and where it runs in there - and\n * without this that sentence was thrown away. [확인함] 2026-09-11\n */\n content: element => element.getAttribute('data-reactive-tooltip') || element.textContent?.trim() || ''\n })\n\n render() {\n return html`\n <div head>\n <div this-week>\n <!--\n W37 is the ISO 8601 week designator. The word \"Week\" was English on every screen,\n and Intl has no name for a week number, so the marker carries it instead of a word.\n -->\n ${monthTitle(this.year, this.month)} · W${this.week}\n </div>\n\n <div nav>\n <md-icon-button\n aria-label=${previousWeekLabel()}\n title=${previousWeekLabel()}\n @click=${() => {\n const dayJs = this.getLastDateOfWeek(this.year, this.week)\n const prevWeek = dayJs.subtract(1, 'week')\n this.moveTo(prevWeek.year(), prevWeek.month(), prevWeek.week())\n }}\n >\n <md-icon>chevron_left</md-icon>\n </md-icon-button>\n <md-text-button\n @click=${() => {\n this.moveTo(dayjs().year(), dayjs().month(), dayjs().week())\n }}\n >${todayLabel()}</md-text-button\n >\n <md-icon-button\n aria-label=${nextWeekLabel()}\n title=${nextWeekLabel()}\n @click=${() => {\n const dayJs = this.getLastDateOfWeek(this.year, this.week)\n const nextWeek = dayJs.add(1, 'week')\n this.moveTo(nextWeek.year(), nextWeek.month(), nextWeek.week())\n }}\n >\n <md-icon>chevron_right</md-icon>\n </md-icon-button>\n </div>\n\n <slot></slot>\n </div>\n\n <ol\n @pointerdown=${this.handlePointerDown}\n @pointermove=${this.handlePointerMove}\n @pointerup=${this.handlePointerUp}\n >\n ${this.calendar?.map((date, index) => {\n const [from, to] = this.selections || ([] as any)\n const { date: thisDate } = date\n const selected = from && to && thisDate >= from && thisDate <= to\n\n return html`\n <li\n ?today=${date.today}\n day-of-week\n date\n day-state=${ifDefined(this.dayStateMap?.get(thisDate)?.name)}\n style=${ifDefined(\n this.dayStateMap?.get(thisDate) &&\n `--day-state-color:${this.dayStateMap.get(thisDate)!.color}`\n )}\n .date=${thisDate}\n ?selected=${selected}\n >\n <span date-label>${dayLabel(date.date, !!date.withMonth)} (${weekdayNames()[index]})</span>\n </li>\n `\n })}\n ${this.calendar?.map(date => {\n const [from, to] = this.selections || ([] as any)\n const { date: thisDate } = date\n const selected = from && to && thisDate >= from && thisDate <= to\n\n /*\n * The event cell carries today as well as the date cell above it.\n *\n * This view draws a day as two cells in one column - the date on top, its events\n * under it - and only the top one was marked. Today's tint therefore stopped at the\n * date band, which is the part you are least likely to be looking at.\n */\n const dayState = this.dayStateMap?.get(thisDate)\n\n return html`<li\n date\n ?today=${date.today}\n day-state=${ifDefined(dayState?.name)}\n style=${ifDefined(dayState && `--day-state-color:${dayState.color}`)}\n .date=${thisDate}\n ?selected=${selected}\n >\n <div>\n ${(this.eventMap?.get(date?.date) || []).map(({ title, color, template }) =>\n template ? template : html`<span event style=\"border-color: ${color};\">${title}</span>`\n )}\n </div>\n </li>`\n })}\n </ol>\n `\n }\n\n async updated(changes: PropertyValues<this>) {\n if (changes.has('year') || changes.has('month') || changes.has('week') || changes.has('eventProvider')) {\n const calendar = this.createDaysForCurrentWeek(this.year, this.week)\n\n /* Both questions go out together — see the month view for why. */\n const [eventMap, dayStateMap] = await Promise.all([\n this.eventProvider?.fetchEventsForCalendar(calendar),\n this.eventProvider?.fetchDayStatesForCalendar?.(calendar)\n ])\n\n this.eventMap = eventMap\n this.dayStateMap = dayStateMap\n this.calendar = calendar\n }\n\n /*\n * After the rows are laid out, not before. A cap only bites once the browser has placed the\n * children, so this has to run on every render - the grid also reflows when the host swaps\n * its templates or the window changes width.\n */\n this.lastOverflow = reportDayOverflow(this, this.shadowRoot, this.lastOverflow)\n }\n\n moveTo(year: number, month: number, week: number) {\n this.year = year\n this.month = month\n this.week = week\n }\n\n handlePointerDown(event: PointerEvent) {\n const target = event.target as HTMLElement\n\n if (!target.hasAttribute('date') && !target.hasAttribute('date-label')) {\n return\n }\n\n const dateElement = target.closest('[date]') as HTMLElement\n const from = (dateElement as any).date\n\n this.pointerDownDate = from\n\n // 캡처를 설정하지 않음(Touch 디바이스에서 중요)\n target.releasePointerCapture(event.pointerId)\n\n event.preventDefault()\n }\n\n handlePointerMove(event: PointerEvent) {\n const from = this.pointerDownDate\n\n if (!from) {\n return\n }\n\n const target = event.target as HTMLElement\n const dateElement = target.closest('[date]') as HTMLElement\n\n if (!dateElement) {\n return\n }\n\n const date = (dateElement as any).date\n this.selections = from > date ? [date, from] : [from, date]\n\n // 캡처를 설정하지 않음(Touch 디바이스에서 중요)\n target.releasePointerCapture(event.pointerId)\n\n event.preventDefault()\n }\n\n handlePointerUp(event: PointerEvent) {\n const from = this.pointerDownDate\n\n this.pointerDownDate = null\n\n if (!from) {\n return\n }\n\n const target = event.target as HTMLElement\n const dateElement = target.closest('[date]') as HTMLElement\n\n if (!dateElement) {\n return\n }\n\n const date = (dateElement as any).date\n this.selections = from > date ? [date, from] : [from, date]\n\n this.dispatchEvent(\n new CustomEvent('select-date', {\n detail: this.selections,\n bubbles: true,\n composed: true\n })\n )\n\n event.preventDefault()\n }\n\n selectDate(date: { label: string; date: Date; thisMonth?: boolean; thisWeek?: boolean; today?: boolean }) {\n if (date) {\n this.selections = [date.date, date.date]\n } else {\n this.selections = undefined\n }\n\n this.dispatchEvent(\n new CustomEvent('select-date', {\n detail: date,\n bubbles: true,\n composed: true\n })\n )\n }\n\n getLastDateOfWeek(year: number, week: number): Dayjs {\n const firstWeekLastDay = dayjs(new Date(year, 0, 1)).endOf('w')\n week -= 1 // one-based week, so need the minus-one\n return firstWeekLastDay.add(week, 'w')\n }\n\n createDaysForCurrentWeek(year: number, week: number): CALENDAR {\n const lastDayjs = this.getLastDateOfWeek(year, week)\n const weekDays = 7\n\n return [...Array(weekDays)]\n .map((day, index) => {\n const date = new Date(lastDayjs.year(), lastDayjs.month(), lastDayjs.date() - index)\n const label = dayLabel(date, true)\n return {\n date,\n label,\n thisWeek: true,\n today: isToday(date)\n }\n })\n .reverse()\n }\n}\n"]}