@luckydraw/blex 0.1.2 → 0.1.4

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.
@@ -27,12 +27,28 @@ function getWeekStart(date) {
27
27
  d.setDate(d.getDate() - d.getDay());
28
28
  return d;
29
29
  }
30
+ function formatTime(iso) {
31
+ const d = new Date(iso);
32
+ if (isNaN(d.getTime())) return iso;
33
+ const h = d.getHours();
34
+ const m = d.getMinutes();
35
+ const ampm = h >= 12 ? "PM" : "AM";
36
+ const h12 = h % 12 || 12;
37
+ return m === 0 ? `${h12} ${ampm}` : `${h12}:${String(m).padStart(2, "0")} ${ampm}`;
38
+ }
39
+ function formatDateReadable(iso) {
40
+ const d = new Date(iso);
41
+ if (isNaN(d.getTime())) return iso;
42
+ const shortMonths = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
43
+ return `${shortMonths[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;
44
+ }
30
45
  var CalendarRenderer = class extends BaseRenderer {
31
46
  constructor() {
32
47
  super(...arguments);
33
48
  this.currentBlock = null;
34
49
  this.viewDate = /* @__PURE__ */ new Date();
35
50
  this.currentView = "month";
51
+ this.activeDetailEl = null;
36
52
  }
37
53
  render(block, container) {
38
54
  this.container = container;
@@ -44,8 +60,59 @@ var CalendarRenderer = class extends BaseRenderer {
44
60
  }
45
61
  revertInteraction(_interaction) {
46
62
  }
63
+ // ---------------------------------------------------------------------------
64
+ // Event detail panel
65
+ // ---------------------------------------------------------------------------
66
+ dismissDetail() {
67
+ if (this.activeDetailEl) {
68
+ this.activeDetailEl.remove();
69
+ this.activeDetailEl = null;
70
+ }
71
+ }
72
+ showDetailPanel(event, _anchor, block) {
73
+ this.dismissDetail();
74
+ const panel = document.createElement("div");
75
+ panel.className = "blex-calendar__detail";
76
+ panel.setAttribute("data-testid", `blex-calendar-detail-${event.id}`);
77
+ const colorBar = document.createElement("div");
78
+ colorBar.className = "blex-calendar__detail-color";
79
+ colorBar.style.backgroundColor = event.color ?? "var(--blex-accent)";
80
+ panel.appendChild(colorBar);
81
+ const content = document.createElement("div");
82
+ content.className = "blex-calendar__detail-content";
83
+ const title = document.createElement("div");
84
+ title.className = "blex-calendar__detail-title";
85
+ title.textContent = event.title;
86
+ content.appendChild(title);
87
+ const time = document.createElement("div");
88
+ time.className = "blex-calendar__detail-time";
89
+ const startDate = formatDateReadable(event.start);
90
+ const startTime = formatTime(event.start);
91
+ const endTime = formatTime(event.end);
92
+ const sameDay = event.start.slice(0, 10) === event.end.slice(0, 10);
93
+ time.textContent = sameDay ? `${startDate}, ${startTime} \u2013 ${endTime}` : `${formatDateReadable(event.start)} ${startTime} \u2013 ${formatDateReadable(event.end)} ${endTime}`;
94
+ content.appendChild(time);
95
+ panel.appendChild(content);
96
+ const dismiss = document.createElement("button");
97
+ dismiss.className = "blex-calendar__detail-dismiss";
98
+ dismiss.setAttribute("data-testid", `blex-calendar-detail-dismiss-${block.id}`);
99
+ dismiss.textContent = "Dismiss";
100
+ this.addListener(dismiss, "click", ((e) => {
101
+ e.stopPropagation();
102
+ this.dismissDetail();
103
+ }));
104
+ panel.appendChild(dismiss);
105
+ const root = this.container?.querySelector(".blex-calendar");
106
+ if (root) {
107
+ root.appendChild(panel);
108
+ } else {
109
+ this.container?.appendChild(panel);
110
+ }
111
+ this.activeDetailEl = panel;
112
+ }
47
113
  update(block) {
48
114
  if (!this.container) return;
115
+ this.activeDetailEl = null;
49
116
  this.currentBlock = block;
50
117
  if (block.data.view) {
51
118
  this.currentView = block.data.view;
@@ -302,6 +369,7 @@ var CalendarRenderer = class extends BaseRenderer {
302
369
  }
303
370
  this.addListener(el, "click", ((e) => {
304
371
  e.stopPropagation();
372
+ this.showDetailPanel(event, el, block);
305
373
  this.emit({
306
374
  blockId: block.id,
307
375
  type: "select",
@@ -328,5 +396,5 @@ function createCalendarRenderer() {
328
396
  }
329
397
 
330
398
  export { CalendarRenderer, createCalendarRenderer };
331
- //# sourceMappingURL=calendar-PNRNENA4.js.map
332
- //# sourceMappingURL=calendar-PNRNENA4.js.map
399
+ //# sourceMappingURL=calendar-DOOC3ERV.js.map
400
+ //# sourceMappingURL=calendar-DOOC3ERV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/renderers/calendar.ts"],"names":[],"mappings":"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","file":"calendar-DOOC3ERV.js","sourcesContent":["import { BaseRenderer } from '../base-renderer.js';\nimport type { ContentBlock, BlockInteraction } from '../types.js';\n\nexport interface CalendarEvent {\n id: string;\n title: string;\n start: string;\n end: string;\n color?: string;\n}\n\nexport type CalendarView = 'month' | 'week' | 'day';\n\nexport interface CalendarData {\n events: CalendarEvent[];\n view?: CalendarView;\n initialDate?: string;\n}\n\nconst DAY_NAMES = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n\nconst MONTH_NAMES = [\n 'January', 'February', 'March', 'April', 'May', 'June',\n 'July', 'August', 'September', 'October', 'November', 'December',\n];\n\n/** Format a Date as \"YYYY-MM-DD\". */\nfunction formatDate(date: Date): string {\n const y = date.getFullYear();\n const m = String(date.getMonth() + 1).padStart(2, '0');\n const d = String(date.getDate()).padStart(2, '0');\n return `${y}-${m}-${d}`;\n}\n\n/** Return the first day (Sunday) of the week containing date. */\nfunction getWeekStart(date: Date): Date {\n const d = new Date(date);\n d.setDate(d.getDate() - d.getDay());\n return d;\n}\n\n/** Format an ISO datetime string as a readable time like \"2:00 PM\". */\nfunction formatTime(iso: string): string {\n const d = new Date(iso);\n if (isNaN(d.getTime())) return iso;\n const h = d.getHours();\n const m = d.getMinutes();\n const ampm = h >= 12 ? 'PM' : 'AM';\n const h12 = h % 12 || 12;\n return m === 0 ? `${h12} ${ampm}` : `${h12}:${String(m).padStart(2, '0')} ${ampm}`;\n}\n\n/** Format an ISO datetime as a readable date like \"Mar 25, 2026\". */\nfunction formatDateReadable(iso: string): string {\n const d = new Date(iso);\n if (isNaN(d.getTime())) return iso;\n const shortMonths = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n return `${shortMonths[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;\n}\n\nexport class CalendarRenderer extends BaseRenderer<CalendarData> {\n private currentBlock: ContentBlock<CalendarData> | null = null;\n private viewDate: Date = new Date();\n private currentView: CalendarView = 'month';\n private activeDetailEl: HTMLElement | null = null;\n\n render(block: ContentBlock<CalendarData>, container: HTMLElement): void {\n this.container = container;\n this.currentBlock = block;\n this.currentView = block.data.view ?? 'month';\n this.viewDate = block.data.initialDate\n ? new Date(block.data.initialDate)\n : new Date();\n this.buildCalendar(block);\n container.setAttribute('data-blex-ready', 'true');\n }\n\n revertInteraction(_interaction: BlockInteraction): void {\n // Calendar interactions (select, slot-click) don't mutate local state,\n // so revert is a no-op on the renderer side. The consumer just removes the chip.\n }\n\n // ---------------------------------------------------------------------------\n // Event detail panel\n // ---------------------------------------------------------------------------\n\n private dismissDetail(): void {\n if (this.activeDetailEl) {\n this.activeDetailEl.remove();\n this.activeDetailEl = null;\n }\n }\n\n private showDetailPanel(event: CalendarEvent, _anchor: HTMLElement, block: ContentBlock<CalendarData>): void {\n this.dismissDetail();\n\n const panel = document.createElement('div');\n panel.className = 'blex-calendar__detail';\n panel.setAttribute('data-testid', `blex-calendar-detail-${event.id}`);\n\n // Color bar\n const colorBar = document.createElement('div');\n colorBar.className = 'blex-calendar__detail-color';\n colorBar.style.backgroundColor = event.color ?? 'var(--blex-accent)';\n panel.appendChild(colorBar);\n\n // Content area\n const content = document.createElement('div');\n content.className = 'blex-calendar__detail-content';\n\n const title = document.createElement('div');\n title.className = 'blex-calendar__detail-title';\n title.textContent = event.title;\n content.appendChild(title);\n\n const time = document.createElement('div');\n time.className = 'blex-calendar__detail-time';\n const startDate = formatDateReadable(event.start);\n const startTime = formatTime(event.start);\n const endTime = formatTime(event.end);\n // Check if same day\n const sameDay = event.start.slice(0, 10) === event.end.slice(0, 10);\n time.textContent = sameDay\n ? `${startDate}, ${startTime} – ${endTime}`\n : `${formatDateReadable(event.start)} ${startTime} – ${formatDateReadable(event.end)} ${endTime}`;\n content.appendChild(time);\n\n panel.appendChild(content);\n\n // Dismiss button\n const dismiss = document.createElement('button');\n dismiss.className = 'blex-calendar__detail-dismiss';\n dismiss.setAttribute('data-testid', `blex-calendar-detail-dismiss-${block.id}`);\n dismiss.textContent = 'Dismiss';\n this.addListener(dismiss, 'click', ((e: MouseEvent) => {\n e.stopPropagation();\n this.dismissDetail();\n }) as EventListener);\n panel.appendChild(dismiss);\n\n // Position: insert after the anchor's parent calendar root\n const root = this.container?.querySelector('.blex-calendar');\n if (root) {\n root.appendChild(panel);\n } else {\n this.container?.appendChild(panel);\n }\n\n this.activeDetailEl = panel;\n }\n\n update(block: ContentBlock<CalendarData>): void {\n if (!this.container) return;\n this.activeDetailEl = null;\n this.currentBlock = block;\n if (block.data.view) {\n this.currentView = block.data.view;\n }\n this.container.innerHTML = '';\n this.buildCalendar(block);\n }\n\n // ---------------------------------------------------------------------------\n // Top-level builder\n // ---------------------------------------------------------------------------\n\n private buildCalendar(block: ContentBlock<CalendarData>): void {\n const container = this.container!;\n\n const root = document.createElement('div');\n root.className = 'blex-calendar';\n root.setAttribute('data-testid', `blex-calendar-${block.id}`);\n\n root.appendChild(this.buildViewToggle(block));\n root.appendChild(this.buildNav(block));\n\n const grid = document.createElement('div');\n grid.className = 'blex-calendar__grid';\n\n if (this.currentView === 'month') {\n this.buildMonthGrid(grid, block);\n } else if (this.currentView === 'week') {\n this.buildWeekGrid(grid, block);\n } else {\n this.buildDayGrid(grid, block);\n }\n\n root.appendChild(grid);\n container.appendChild(root);\n }\n\n // ---------------------------------------------------------------------------\n // View toggle\n // ---------------------------------------------------------------------------\n\n private buildViewToggle(block: ContentBlock<CalendarData>): HTMLElement {\n const bar = document.createElement('div');\n bar.className = 'blex-calendar__view-toggle';\n\n const views: CalendarView[] = ['month', 'week', 'day'];\n for (const v of views) {\n const btn = document.createElement('button');\n btn.className = 'blex-calendar__view-btn';\n btn.setAttribute('data-testid', `blex-calendar-view-${v}`);\n btn.textContent = v.charAt(0).toUpperCase() + v.slice(1);\n if (v === this.currentView) {\n btn.setAttribute('aria-pressed', 'true');\n }\n\n this.addListener(btn, 'click', (() => {\n this.currentView = v;\n this.container!.innerHTML = '';\n this.buildCalendar(block);\n }) as EventListener);\n\n bar.appendChild(btn);\n }\n\n return bar;\n }\n\n // ---------------------------------------------------------------------------\n // Navigation bar\n // ---------------------------------------------------------------------------\n\n private buildNav(block: ContentBlock<CalendarData>): HTMLElement {\n const nav = document.createElement('div');\n nav.className = 'blex-calendar__nav';\n\n const prev = document.createElement('button');\n prev.className = 'blex-calendar__nav-btn';\n prev.setAttribute('data-testid', `blex-calendar-prev-${block.id}`);\n prev.textContent = '‹';\n this.addListener(prev, 'click', (() => {\n this.navigate(-1);\n }) as EventListener);\n\n const title = document.createElement('span');\n title.className = 'blex-calendar__title';\n title.textContent = this.getHeaderTitle();\n\n const next = document.createElement('button');\n next.className = 'blex-calendar__nav-btn';\n next.setAttribute('data-testid', `blex-calendar-next-${block.id}`);\n next.textContent = '›';\n this.addListener(next, 'click', (() => {\n this.navigate(1);\n }) as EventListener);\n\n nav.appendChild(prev);\n nav.appendChild(title);\n nav.appendChild(next);\n return nav;\n }\n\n private getHeaderTitle(): string {\n if (this.currentView === 'month') {\n return `${MONTH_NAMES[this.viewDate.getMonth()]} ${this.viewDate.getFullYear()}`;\n } else if (this.currentView === 'week') {\n const start = getWeekStart(this.viewDate);\n const end = new Date(start);\n end.setDate(end.getDate() + 6);\n return `${MONTH_NAMES[start.getMonth()]} ${start.getDate()} – ${end.getDate()}, ${start.getFullYear()}`;\n } else {\n return `${MONTH_NAMES[this.viewDate.getMonth()]} ${this.viewDate.getDate()}, ${this.viewDate.getFullYear()}`;\n }\n }\n\n private navigate(direction: number): void {\n if (this.currentView === 'month') {\n this.viewDate.setMonth(this.viewDate.getMonth() + direction);\n } else if (this.currentView === 'week') {\n this.viewDate.setDate(this.viewDate.getDate() + direction * 7);\n } else {\n this.viewDate.setDate(this.viewDate.getDate() + direction);\n }\n this.container!.innerHTML = '';\n this.buildCalendar(this.currentBlock!);\n }\n\n // ---------------------------------------------------------------------------\n // Month grid\n // ---------------------------------------------------------------------------\n\n private buildMonthGrid(grid: HTMLElement, block: ContentBlock<CalendarData>): void {\n const year = this.viewDate.getFullYear();\n const month = this.viewDate.getMonth();\n\n // Day-of-week header row\n for (const name of DAY_NAMES) {\n const hdr = document.createElement('div');\n hdr.className = 'blex-calendar__day-header';\n hdr.textContent = name;\n grid.appendChild(hdr);\n }\n\n const firstDay = new Date(year, month, 1).getDay();\n const daysInMonth = new Date(year, month + 1, 0).getDate();\n\n // Blank cells before the 1st\n for (let i = 0; i < firstDay; i++) {\n const blank = document.createElement('div');\n blank.className = 'blex-calendar__day blex-calendar__day--filler';\n grid.appendChild(blank);\n }\n\n // Day cells\n for (let day = 1; day <= daysInMonth; day++) {\n const mm = String(month + 1).padStart(2, '0');\n const dd = String(day).padStart(2, '0');\n const dateStr = `${year}-${mm}-${dd}`;\n const cell = document.createElement('div');\n cell.className = 'blex-calendar__day';\n cell.setAttribute('data-testid', `blex-calendar-day-${dateStr}`);\n cell.setAttribute('data-date', dateStr);\n\n const dayNum = document.createElement('span');\n dayNum.className = 'blex-calendar__day-number';\n dayNum.textContent = String(day);\n cell.appendChild(dayNum);\n\n // Events inside this day cell\n const dayEvents = this.getEventsForDate(block.data.events, dateStr);\n for (const event of dayEvents) {\n cell.appendChild(this.buildEventEl(event, block));\n }\n\n // Clicking on the day cell (not on an event) emits slot-click\n this.addListener(cell, 'click', ((e: MouseEvent) => {\n if ((e.target as HTMLElement).closest('.blex-calendar__event')) return;\n const start = `${dateStr}T00:00`;\n const end = `${dateStr}T23:59`;\n this.emit({\n blockId: block.id,\n type: 'slot-click',\n payload: { start, end },\n serialized: `Selected time slot: ${start} - ${end}`,\n summary: `Selected slot: ${start}`,\n icon: '📅',\n immediate: false,\n revertable: true,\n });\n }) as EventListener);\n\n grid.appendChild(cell);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Week grid (structural)\n // ---------------------------------------------------------------------------\n\n private buildWeekGrid(grid: HTMLElement, block: ContentBlock<CalendarData>): void {\n const weekStart = getWeekStart(this.viewDate);\n\n for (let i = 0; i < 7; i++) {\n const day = new Date(weekStart);\n day.setDate(weekStart.getDate() + i);\n const dateStr = formatDate(day);\n\n const col = document.createElement('div');\n col.className = 'blex-calendar__day';\n col.setAttribute('data-testid', `blex-calendar-day-${dateStr}`);\n col.setAttribute('data-date', dateStr);\n\n const hdr = document.createElement('div');\n hdr.className = 'blex-calendar__day-header';\n hdr.textContent = `${DAY_NAMES[day.getDay()]} ${day.getDate()}`;\n col.appendChild(hdr);\n\n // Hourly slots\n for (let hour = 0; hour < 24; hour++) {\n const hourStr = String(hour).padStart(2, '0');\n const slotStart = `${dateStr}T${hourStr}:00`;\n const slotEnd = `${dateStr}T${hourStr}:59`;\n\n const slot = document.createElement('div');\n slot.className = 'blex-calendar__slot';\n slot.setAttribute('data-start', slotStart);\n slot.setAttribute('data-end', slotEnd);\n slot.textContent = `${hourStr}:00`;\n\n this.addListener(slot, 'click', (() => {\n this.emit({\n blockId: block.id,\n type: 'slot-click',\n payload: { start: slotStart, end: slotEnd },\n serialized: `Selected time slot: ${slotStart} - ${slotEnd}`,\n summary: `Selected slot: ${slotStart}`,\n icon: '📅',\n immediate: false,\n revertable: true,\n });\n }) as EventListener);\n\n col.appendChild(slot);\n }\n\n // Events for this day\n const dayEvents = this.getEventsForDate(block.data.events, dateStr);\n for (const event of dayEvents) {\n col.appendChild(this.buildEventEl(event, block));\n }\n\n grid.appendChild(col);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Day grid (structural)\n // ---------------------------------------------------------------------------\n\n private buildDayGrid(grid: HTMLElement, block: ContentBlock<CalendarData>): void {\n const dateStr = formatDate(this.viewDate);\n\n const col = document.createElement('div');\n col.className = 'blex-calendar__day';\n col.setAttribute('data-testid', `blex-calendar-day-${dateStr}`);\n col.setAttribute('data-date', dateStr);\n\n // Hourly slots\n for (let hour = 0; hour < 24; hour++) {\n const hourStr = String(hour).padStart(2, '0');\n const slotStart = `${dateStr}T${hourStr}:00`;\n const slotEnd = `${dateStr}T${hourStr}:59`;\n\n const slot = document.createElement('div');\n slot.className = 'blex-calendar__slot';\n slot.setAttribute('data-start', slotStart);\n slot.setAttribute('data-end', slotEnd);\n slot.textContent = `${hourStr}:00`;\n\n this.addListener(slot, 'click', (() => {\n this.emit({\n blockId: block.id,\n type: 'slot-click',\n payload: { start: slotStart, end: slotEnd },\n serialized: `Selected time slot: ${slotStart} - ${slotEnd}`,\n summary: `Selected slot: ${slotStart}`,\n icon: '📅',\n immediate: false,\n revertable: true,\n });\n }) as EventListener);\n\n col.appendChild(slot);\n }\n\n // Events for this day\n const dayEvents = this.getEventsForDate(block.data.events, dateStr);\n for (const event of dayEvents) {\n col.appendChild(this.buildEventEl(event, block));\n }\n\n grid.appendChild(col);\n }\n\n // ---------------------------------------------------------------------------\n // Shared helpers\n // ---------------------------------------------------------------------------\n\n private buildEventEl(event: CalendarEvent, block: ContentBlock<CalendarData>): HTMLElement {\n const el = document.createElement('div');\n el.className = 'blex-calendar__event';\n el.setAttribute('data-testid', `blex-calendar-event-${event.id}`);\n el.setAttribute('data-event-id', event.id);\n el.textContent = event.title;\n\n if (event.color) {\n el.style.backgroundColor = event.color;\n }\n\n this.addListener(el, 'click', ((e: MouseEvent) => {\n e.stopPropagation();\n this.showDetailPanel(event, el, block);\n this.emit({\n blockId: block.id,\n type: 'select',\n payload: { eventId: event.id },\n serialized: `Selected event: ${event.title}`,\n summary: `Viewed \"${event.title}\"`,\n icon: '📅',\n immediate: false,\n revertable: true,\n });\n }) as EventListener);\n\n return el;\n }\n\n private getEventsForDate(events: CalendarEvent[], dateStr: string): CalendarEvent[] {\n return events.filter((event) => {\n const eventStart = event.start.slice(0, 10);\n const eventEnd = event.end.slice(0, 10);\n return dateStr >= eventStart && dateStr <= eventEnd;\n });\n }\n}\n\nexport function createCalendarRenderer(): CalendarRenderer {\n return new CalendarRenderer();\n}\n"]}