@luckydraw/blex 0.1.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.
- package/README.md +298 -0
- package/dist/blex-chart.min.global.js +23 -0
- package/dist/blex-chart.min.global.js.map +1 -0
- package/dist/blex.min.global.js +105 -0
- package/dist/blex.min.global.js.map +1 -0
- package/dist/esm/base-renderer.d.ts +28 -0
- package/dist/esm/base-renderer.d.ts.map +1 -0
- package/dist/esm/calendar-HUZDQQN2.js +314 -0
- package/dist/esm/calendar-HUZDQQN2.js.map +1 -0
- package/dist/esm/chart/index.d.ts +14 -0
- package/dist/esm/chart/index.d.ts.map +1 -0
- package/dist/esm/chart/index.js +3 -0
- package/dist/esm/chart/index.js.map +1 -0
- package/dist/esm/chart-2QT47W6E.js +38 -0
- package/dist/esm/chart-2QT47W6E.js.map +1 -0
- package/dist/esm/chunk-ODHF7VXV.js +74 -0
- package/dist/esm/chunk-ODHF7VXV.js.map +1 -0
- package/dist/esm/chunk-PBRPD4A5.js +91 -0
- package/dist/esm/chunk-PBRPD4A5.js.map +1 -0
- package/dist/esm/chunk-ZKSJGHJI.js +1573 -0
- package/dist/esm/chunk-ZKSJGHJI.js.map +1 -0
- package/dist/esm/defaults.d.ts +6 -0
- package/dist/esm/defaults.d.ts.map +1 -0
- package/dist/esm/fallback.d.ts +11 -0
- package/dist/esm/fallback.d.ts.map +1 -0
- package/dist/esm/gallery-ISM7FZA3.js +130 -0
- package/dist/esm/gallery-ISM7FZA3.js.map +1 -0
- package/dist/esm/index.d.ts +8 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +91 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/kanban-XUXVTRX2.js +126 -0
- package/dist/esm/kanban-XUXVTRX2.js.map +1 -0
- package/dist/esm/mermaid-W3HX2CK2.js +130 -0
- package/dist/esm/mermaid-W3HX2CK2.js.map +1 -0
- package/dist/esm/placeholder.d.ts +8 -0
- package/dist/esm/placeholder.d.ts.map +1 -0
- package/dist/esm/plugin.d.ts +34 -0
- package/dist/esm/plugin.d.ts.map +1 -0
- package/dist/esm/react/chart.d.ts +12 -0
- package/dist/esm/react/chart.d.ts.map +1 -0
- package/dist/esm/react/chart.js +50 -0
- package/dist/esm/react/chart.js.map +1 -0
- package/dist/esm/react/index.d.ts +13 -0
- package/dist/esm/react/index.d.ts.map +1 -0
- package/dist/esm/react/index.js +66 -0
- package/dist/esm/react/index.js.map +1 -0
- package/dist/esm/registry.d.ts +46 -0
- package/dist/esm/registry.d.ts.map +1 -0
- package/dist/esm/render.d.ts +13 -0
- package/dist/esm/render.d.ts.map +1 -0
- package/dist/esm/renderers/calendar.d.ts +34 -0
- package/dist/esm/renderers/calendar.d.ts.map +1 -0
- package/dist/esm/renderers/chart.d.ts +12 -0
- package/dist/esm/renderers/chart.d.ts.map +1 -0
- package/dist/esm/renderers/code.d.ts +19 -0
- package/dist/esm/renderers/code.d.ts.map +1 -0
- package/dist/esm/renderers/confirm.d.ts +13 -0
- package/dist/esm/renderers/confirm.d.ts.map +1 -0
- package/dist/esm/renderers/diff.d.ts +24 -0
- package/dist/esm/renderers/diff.d.ts.map +1 -0
- package/dist/esm/renderers/file-tree.d.ts +24 -0
- package/dist/esm/renderers/file-tree.d.ts.map +1 -0
- package/dist/esm/renderers/form.d.ts +27 -0
- package/dist/esm/renderers/form.d.ts.map +1 -0
- package/dist/esm/renderers/gallery.d.ts +24 -0
- package/dist/esm/renderers/gallery.d.ts.map +1 -0
- package/dist/esm/renderers/image.d.ts +17 -0
- package/dist/esm/renderers/image.d.ts.map +1 -0
- package/dist/esm/renderers/kanban.d.ts +29 -0
- package/dist/esm/renderers/kanban.d.ts.map +1 -0
- package/dist/esm/renderers/layout.d.ts +17 -0
- package/dist/esm/renderers/layout.d.ts.map +1 -0
- package/dist/esm/renderers/mermaid.d.ts +19 -0
- package/dist/esm/renderers/mermaid.d.ts.map +1 -0
- package/dist/esm/renderers/metric.d.ts +16 -0
- package/dist/esm/renderers/metric.d.ts.map +1 -0
- package/dist/esm/renderers/poll.d.ts +17 -0
- package/dist/esm/renderers/poll.d.ts.map +1 -0
- package/dist/esm/renderers/progress.d.ts +18 -0
- package/dist/esm/renderers/progress.d.ts.map +1 -0
- package/dist/esm/renderers/status.d.ts +17 -0
- package/dist/esm/renderers/status.d.ts.map +1 -0
- package/dist/esm/renderers/svg.d.ts +13 -0
- package/dist/esm/renderers/svg.d.ts.map +1 -0
- package/dist/esm/renderers/table.d.ts +20 -0
- package/dist/esm/renderers/table.d.ts.map +1 -0
- package/dist/esm/renderers/terminal.d.ts +16 -0
- package/dist/esm/renderers/terminal.d.ts.map +1 -0
- package/dist/esm/renderers/timeline.d.ts +20 -0
- package/dist/esm/renderers/timeline.d.ts.map +1 -0
- package/dist/esm/theme.d.ts +10 -0
- package/dist/esm/theme.d.ts.map +1 -0
- package/dist/esm/types-C42V92x6.d.ts +75 -0
- package/dist/esm/types.d.ts +81 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { BlockRenderer, ContentBlock, BlockInteraction } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Abstract base class for block renderers. Tracks all resources
|
|
4
|
+
* (event listeners, timers, RAF, observers) and releases them on destroy().
|
|
5
|
+
*
|
|
6
|
+
* All built-in renderers extend this class to guarantee zero leaks.
|
|
7
|
+
*/
|
|
8
|
+
export declare abstract class BaseRenderer<T = unknown> implements BlockRenderer<T> {
|
|
9
|
+
protected container: HTMLElement | null;
|
|
10
|
+
protected interactionCallback: ((interaction: BlockInteraction) => void) | null;
|
|
11
|
+
private trackedListeners;
|
|
12
|
+
private trackedTimers;
|
|
13
|
+
private trackedRAFs;
|
|
14
|
+
private trackedObservers;
|
|
15
|
+
private destroyed;
|
|
16
|
+
abstract render(block: ContentBlock<T>, container: HTMLElement): void;
|
|
17
|
+
update?(block: ContentBlock<T>): void;
|
|
18
|
+
onInteraction(callback: (interaction: BlockInteraction) => void): void;
|
|
19
|
+
destroy(): void;
|
|
20
|
+
protected addListener(target: EventTarget, type: string, listener: EventListener): void;
|
|
21
|
+
protected setTimeout(fn: () => void, ms: number): number;
|
|
22
|
+
protected setInterval(fn: () => void, ms: number): number;
|
|
23
|
+
protected requestAnimationFrame(fn: FrameRequestCallback): number;
|
|
24
|
+
protected trackObserver(observer: ResizeObserver | MutationObserver | IntersectionObserver): void;
|
|
25
|
+
protected emit(interaction: BlockInteraction): void;
|
|
26
|
+
protected get isDestroyed(): boolean;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=base-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-renderer.d.ts","sourceRoot":"","sources":["../../src/base-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEhF;;;;;GAKG;AACH,8BAAsB,YAAY,CAAC,CAAC,GAAG,OAAO,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;IACzE,SAAS,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,CAAQ;IAC/C,SAAS,CAAC,mBAAmB,EAAE,CAAC,CAAC,WAAW,EAAE,gBAAgB,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IAEvF,OAAO,CAAC,gBAAgB,CAA6E;IACrG,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,gBAAgB,CAAuE;IAC/F,OAAO,CAAC,SAAS,CAAS;IAE1B,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,WAAW,GAAG,IAAI;IAErE,MAAM,CAAC,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI;IAErC,aAAa,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,gBAAgB,KAAK,IAAI,GAAG,IAAI;IAItE,OAAO,IAAI,IAAI;IAwCf,SAAS,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAKvF,SAAS,CAAC,UAAU,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM;IAMxD,SAAS,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM;IAMzD,SAAS,CAAC,qBAAqB,CAAC,EAAE,EAAE,oBAAoB,GAAG,MAAM;IAMjE,SAAS,CAAC,aAAa,CAAC,QAAQ,EAAE,cAAc,GAAG,gBAAgB,GAAG,oBAAoB,GAAG,IAAI;IAIjG,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,gBAAgB,GAAG,IAAI;IAInD,SAAS,KAAK,WAAW,IAAI,OAAO,CAEnC;CACF"}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { BaseRenderer } from './chunk-ODHF7VXV.js';
|
|
2
|
+
|
|
3
|
+
// src/renderers/calendar.ts
|
|
4
|
+
var DAY_NAMES = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
5
|
+
var MONTH_NAMES = [
|
|
6
|
+
"January",
|
|
7
|
+
"February",
|
|
8
|
+
"March",
|
|
9
|
+
"April",
|
|
10
|
+
"May",
|
|
11
|
+
"June",
|
|
12
|
+
"July",
|
|
13
|
+
"August",
|
|
14
|
+
"September",
|
|
15
|
+
"October",
|
|
16
|
+
"November",
|
|
17
|
+
"December"
|
|
18
|
+
];
|
|
19
|
+
function formatDate(date) {
|
|
20
|
+
const y = date.getFullYear();
|
|
21
|
+
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
22
|
+
const d = String(date.getDate()).padStart(2, "0");
|
|
23
|
+
return `${y}-${m}-${d}`;
|
|
24
|
+
}
|
|
25
|
+
function getWeekStart(date) {
|
|
26
|
+
const d = new Date(date);
|
|
27
|
+
d.setDate(d.getDate() - d.getDay());
|
|
28
|
+
return d;
|
|
29
|
+
}
|
|
30
|
+
var CalendarRenderer = class extends BaseRenderer {
|
|
31
|
+
constructor() {
|
|
32
|
+
super(...arguments);
|
|
33
|
+
this.currentBlock = null;
|
|
34
|
+
this.viewDate = /* @__PURE__ */ new Date();
|
|
35
|
+
this.currentView = "month";
|
|
36
|
+
}
|
|
37
|
+
render(block, container) {
|
|
38
|
+
this.container = container;
|
|
39
|
+
this.currentBlock = block;
|
|
40
|
+
this.currentView = block.data.view ?? "month";
|
|
41
|
+
this.viewDate = block.data.initialDate ? new Date(block.data.initialDate) : /* @__PURE__ */ new Date();
|
|
42
|
+
this.buildCalendar(block);
|
|
43
|
+
container.setAttribute("data-blex-ready", "true");
|
|
44
|
+
}
|
|
45
|
+
update(block) {
|
|
46
|
+
if (!this.container) return;
|
|
47
|
+
this.currentBlock = block;
|
|
48
|
+
if (block.data.view) {
|
|
49
|
+
this.currentView = block.data.view;
|
|
50
|
+
}
|
|
51
|
+
this.container.innerHTML = "";
|
|
52
|
+
this.buildCalendar(block);
|
|
53
|
+
}
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Top-level builder
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
buildCalendar(block) {
|
|
58
|
+
const container = this.container;
|
|
59
|
+
const root = document.createElement("div");
|
|
60
|
+
root.className = "blex-calendar";
|
|
61
|
+
root.setAttribute("data-testid", `blex-calendar-${block.id}`);
|
|
62
|
+
root.appendChild(this.buildViewToggle(block));
|
|
63
|
+
root.appendChild(this.buildNav(block));
|
|
64
|
+
const grid = document.createElement("div");
|
|
65
|
+
grid.className = "blex-calendar__grid";
|
|
66
|
+
if (this.currentView === "month") {
|
|
67
|
+
this.buildMonthGrid(grid, block);
|
|
68
|
+
} else if (this.currentView === "week") {
|
|
69
|
+
this.buildWeekGrid(grid, block);
|
|
70
|
+
} else {
|
|
71
|
+
this.buildDayGrid(grid, block);
|
|
72
|
+
}
|
|
73
|
+
root.appendChild(grid);
|
|
74
|
+
container.appendChild(root);
|
|
75
|
+
}
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
// View toggle
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
buildViewToggle(block) {
|
|
80
|
+
const bar = document.createElement("div");
|
|
81
|
+
bar.className = "blex-calendar__view-toggle";
|
|
82
|
+
const views = ["month", "week", "day"];
|
|
83
|
+
for (const v of views) {
|
|
84
|
+
const btn = document.createElement("button");
|
|
85
|
+
btn.className = "blex-calendar__view-btn";
|
|
86
|
+
btn.setAttribute("data-testid", `blex-calendar-view-${v}`);
|
|
87
|
+
btn.textContent = v.charAt(0).toUpperCase() + v.slice(1);
|
|
88
|
+
if (v === this.currentView) {
|
|
89
|
+
btn.setAttribute("aria-pressed", "true");
|
|
90
|
+
}
|
|
91
|
+
this.addListener(btn, "click", (() => {
|
|
92
|
+
this.currentView = v;
|
|
93
|
+
this.container.innerHTML = "";
|
|
94
|
+
this.buildCalendar(block);
|
|
95
|
+
}));
|
|
96
|
+
bar.appendChild(btn);
|
|
97
|
+
}
|
|
98
|
+
return bar;
|
|
99
|
+
}
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
// Navigation bar
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
buildNav(block) {
|
|
104
|
+
const nav = document.createElement("div");
|
|
105
|
+
nav.className = "blex-calendar__nav";
|
|
106
|
+
const prev = document.createElement("button");
|
|
107
|
+
prev.className = "blex-calendar__nav-btn";
|
|
108
|
+
prev.setAttribute("data-testid", `blex-calendar-prev-${block.id}`);
|
|
109
|
+
prev.textContent = "\u2039";
|
|
110
|
+
this.addListener(prev, "click", (() => {
|
|
111
|
+
this.navigate(-1);
|
|
112
|
+
}));
|
|
113
|
+
const title = document.createElement("span");
|
|
114
|
+
title.className = "blex-calendar__title";
|
|
115
|
+
title.textContent = this.getHeaderTitle();
|
|
116
|
+
const next = document.createElement("button");
|
|
117
|
+
next.className = "blex-calendar__nav-btn";
|
|
118
|
+
next.setAttribute("data-testid", `blex-calendar-next-${block.id}`);
|
|
119
|
+
next.textContent = "\u203A";
|
|
120
|
+
this.addListener(next, "click", (() => {
|
|
121
|
+
this.navigate(1);
|
|
122
|
+
}));
|
|
123
|
+
nav.appendChild(prev);
|
|
124
|
+
nav.appendChild(title);
|
|
125
|
+
nav.appendChild(next);
|
|
126
|
+
return nav;
|
|
127
|
+
}
|
|
128
|
+
getHeaderTitle() {
|
|
129
|
+
if (this.currentView === "month") {
|
|
130
|
+
return `${MONTH_NAMES[this.viewDate.getMonth()]} ${this.viewDate.getFullYear()}`;
|
|
131
|
+
} else if (this.currentView === "week") {
|
|
132
|
+
const start = getWeekStart(this.viewDate);
|
|
133
|
+
const end = new Date(start);
|
|
134
|
+
end.setDate(end.getDate() + 6);
|
|
135
|
+
return `${MONTH_NAMES[start.getMonth()]} ${start.getDate()} \u2013 ${end.getDate()}, ${start.getFullYear()}`;
|
|
136
|
+
} else {
|
|
137
|
+
return `${MONTH_NAMES[this.viewDate.getMonth()]} ${this.viewDate.getDate()}, ${this.viewDate.getFullYear()}`;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
navigate(direction) {
|
|
141
|
+
if (this.currentView === "month") {
|
|
142
|
+
this.viewDate.setMonth(this.viewDate.getMonth() + direction);
|
|
143
|
+
} else if (this.currentView === "week") {
|
|
144
|
+
this.viewDate.setDate(this.viewDate.getDate() + direction * 7);
|
|
145
|
+
} else {
|
|
146
|
+
this.viewDate.setDate(this.viewDate.getDate() + direction);
|
|
147
|
+
}
|
|
148
|
+
this.container.innerHTML = "";
|
|
149
|
+
this.buildCalendar(this.currentBlock);
|
|
150
|
+
}
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// Month grid
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
buildMonthGrid(grid, block) {
|
|
155
|
+
const year = this.viewDate.getFullYear();
|
|
156
|
+
const month = this.viewDate.getMonth();
|
|
157
|
+
for (const name of DAY_NAMES) {
|
|
158
|
+
const hdr = document.createElement("div");
|
|
159
|
+
hdr.className = "blex-calendar__day-header";
|
|
160
|
+
hdr.textContent = name;
|
|
161
|
+
grid.appendChild(hdr);
|
|
162
|
+
}
|
|
163
|
+
const firstDay = new Date(year, month, 1).getDay();
|
|
164
|
+
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
165
|
+
for (let i = 0; i < firstDay; i++) {
|
|
166
|
+
const blank = document.createElement("div");
|
|
167
|
+
blank.className = "blex-calendar__day blex-calendar__day--filler";
|
|
168
|
+
grid.appendChild(blank);
|
|
169
|
+
}
|
|
170
|
+
for (let day = 1; day <= daysInMonth; day++) {
|
|
171
|
+
const mm = String(month + 1).padStart(2, "0");
|
|
172
|
+
const dd = String(day).padStart(2, "0");
|
|
173
|
+
const dateStr = `${year}-${mm}-${dd}`;
|
|
174
|
+
const cell = document.createElement("div");
|
|
175
|
+
cell.className = "blex-calendar__day";
|
|
176
|
+
cell.setAttribute("data-testid", `blex-calendar-day-${dateStr}`);
|
|
177
|
+
cell.setAttribute("data-date", dateStr);
|
|
178
|
+
const dayNum = document.createElement("span");
|
|
179
|
+
dayNum.className = "blex-calendar__day-number";
|
|
180
|
+
dayNum.textContent = String(day);
|
|
181
|
+
cell.appendChild(dayNum);
|
|
182
|
+
const dayEvents = this.getEventsForDate(block.data.events, dateStr);
|
|
183
|
+
for (const event of dayEvents) {
|
|
184
|
+
cell.appendChild(this.buildEventEl(event, block));
|
|
185
|
+
}
|
|
186
|
+
this.addListener(cell, "click", ((e) => {
|
|
187
|
+
if (e.target.closest(".blex-calendar__event")) return;
|
|
188
|
+
const start = `${dateStr}T00:00`;
|
|
189
|
+
const end = `${dateStr}T23:59`;
|
|
190
|
+
this.emit({
|
|
191
|
+
blockId: block.id,
|
|
192
|
+
type: "slot-click",
|
|
193
|
+
payload: { start, end },
|
|
194
|
+
serialized: `Selected time slot: ${start} - ${end}`
|
|
195
|
+
});
|
|
196
|
+
}));
|
|
197
|
+
grid.appendChild(cell);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
// Week grid (structural)
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
buildWeekGrid(grid, block) {
|
|
204
|
+
const weekStart = getWeekStart(this.viewDate);
|
|
205
|
+
for (let i = 0; i < 7; i++) {
|
|
206
|
+
const day = new Date(weekStart);
|
|
207
|
+
day.setDate(weekStart.getDate() + i);
|
|
208
|
+
const dateStr = formatDate(day);
|
|
209
|
+
const col = document.createElement("div");
|
|
210
|
+
col.className = "blex-calendar__day";
|
|
211
|
+
col.setAttribute("data-testid", `blex-calendar-day-${dateStr}`);
|
|
212
|
+
col.setAttribute("data-date", dateStr);
|
|
213
|
+
const hdr = document.createElement("div");
|
|
214
|
+
hdr.className = "blex-calendar__day-header";
|
|
215
|
+
hdr.textContent = `${DAY_NAMES[day.getDay()]} ${day.getDate()}`;
|
|
216
|
+
col.appendChild(hdr);
|
|
217
|
+
for (let hour = 0; hour < 24; hour++) {
|
|
218
|
+
const hourStr = String(hour).padStart(2, "0");
|
|
219
|
+
const slotStart = `${dateStr}T${hourStr}:00`;
|
|
220
|
+
const slotEnd = `${dateStr}T${hourStr}:59`;
|
|
221
|
+
const slot = document.createElement("div");
|
|
222
|
+
slot.className = "blex-calendar__slot";
|
|
223
|
+
slot.setAttribute("data-start", slotStart);
|
|
224
|
+
slot.setAttribute("data-end", slotEnd);
|
|
225
|
+
slot.textContent = `${hourStr}:00`;
|
|
226
|
+
this.addListener(slot, "click", (() => {
|
|
227
|
+
this.emit({
|
|
228
|
+
blockId: block.id,
|
|
229
|
+
type: "slot-click",
|
|
230
|
+
payload: { start: slotStart, end: slotEnd },
|
|
231
|
+
serialized: `Selected time slot: ${slotStart} - ${slotEnd}`
|
|
232
|
+
});
|
|
233
|
+
}));
|
|
234
|
+
col.appendChild(slot);
|
|
235
|
+
}
|
|
236
|
+
const dayEvents = this.getEventsForDate(block.data.events, dateStr);
|
|
237
|
+
for (const event of dayEvents) {
|
|
238
|
+
col.appendChild(this.buildEventEl(event, block));
|
|
239
|
+
}
|
|
240
|
+
grid.appendChild(col);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// ---------------------------------------------------------------------------
|
|
244
|
+
// Day grid (structural)
|
|
245
|
+
// ---------------------------------------------------------------------------
|
|
246
|
+
buildDayGrid(grid, block) {
|
|
247
|
+
const dateStr = formatDate(this.viewDate);
|
|
248
|
+
const col = document.createElement("div");
|
|
249
|
+
col.className = "blex-calendar__day";
|
|
250
|
+
col.setAttribute("data-testid", `blex-calendar-day-${dateStr}`);
|
|
251
|
+
col.setAttribute("data-date", dateStr);
|
|
252
|
+
for (let hour = 0; hour < 24; hour++) {
|
|
253
|
+
const hourStr = String(hour).padStart(2, "0");
|
|
254
|
+
const slotStart = `${dateStr}T${hourStr}:00`;
|
|
255
|
+
const slotEnd = `${dateStr}T${hourStr}:59`;
|
|
256
|
+
const slot = document.createElement("div");
|
|
257
|
+
slot.className = "blex-calendar__slot";
|
|
258
|
+
slot.setAttribute("data-start", slotStart);
|
|
259
|
+
slot.setAttribute("data-end", slotEnd);
|
|
260
|
+
slot.textContent = `${hourStr}:00`;
|
|
261
|
+
this.addListener(slot, "click", (() => {
|
|
262
|
+
this.emit({
|
|
263
|
+
blockId: block.id,
|
|
264
|
+
type: "slot-click",
|
|
265
|
+
payload: { start: slotStart, end: slotEnd },
|
|
266
|
+
serialized: `Selected time slot: ${slotStart} - ${slotEnd}`
|
|
267
|
+
});
|
|
268
|
+
}));
|
|
269
|
+
col.appendChild(slot);
|
|
270
|
+
}
|
|
271
|
+
const dayEvents = this.getEventsForDate(block.data.events, dateStr);
|
|
272
|
+
for (const event of dayEvents) {
|
|
273
|
+
col.appendChild(this.buildEventEl(event, block));
|
|
274
|
+
}
|
|
275
|
+
grid.appendChild(col);
|
|
276
|
+
}
|
|
277
|
+
// ---------------------------------------------------------------------------
|
|
278
|
+
// Shared helpers
|
|
279
|
+
// ---------------------------------------------------------------------------
|
|
280
|
+
buildEventEl(event, block) {
|
|
281
|
+
const el = document.createElement("div");
|
|
282
|
+
el.className = "blex-calendar__event";
|
|
283
|
+
el.setAttribute("data-testid", `blex-calendar-event-${event.id}`);
|
|
284
|
+
el.setAttribute("data-event-id", event.id);
|
|
285
|
+
el.textContent = event.title;
|
|
286
|
+
if (event.color) {
|
|
287
|
+
el.style.backgroundColor = event.color;
|
|
288
|
+
}
|
|
289
|
+
this.addListener(el, "click", ((e) => {
|
|
290
|
+
e.stopPropagation();
|
|
291
|
+
this.emit({
|
|
292
|
+
blockId: block.id,
|
|
293
|
+
type: "select",
|
|
294
|
+
payload: { eventId: event.id },
|
|
295
|
+
serialized: `Selected event: ${event.title}`
|
|
296
|
+
});
|
|
297
|
+
}));
|
|
298
|
+
return el;
|
|
299
|
+
}
|
|
300
|
+
getEventsForDate(events, dateStr) {
|
|
301
|
+
return events.filter((event) => {
|
|
302
|
+
const eventStart = event.start.slice(0, 10);
|
|
303
|
+
const eventEnd = event.end.slice(0, 10);
|
|
304
|
+
return dateStr >= eventStart && dateStr <= eventEnd;
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
function createCalendarRenderer() {
|
|
309
|
+
return new CalendarRenderer();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export { CalendarRenderer, createCalendarRenderer };
|
|
313
|
+
//# sourceMappingURL=calendar-HUZDQQN2.js.map
|
|
314
|
+
//# sourceMappingURL=calendar-HUZDQQN2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/renderers/calendar.ts"],"names":[],"mappings":"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","file":"calendar-HUZDQQN2.js","sourcesContent":["import { BaseRenderer } from '../base-renderer.js';\nimport type { ContentBlock } 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\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\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 update(block: ContentBlock<CalendarData>): void {\n if (!this.container) return;\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 });\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 });\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 });\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.emit({\n blockId: block.id,\n type: 'select',\n payload: { eventId: event.id },\n serialized: `Selected event: ${event.title}`,\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"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @luckydraw/blex/chart — Standalone chart rendering subpath.
|
|
3
|
+
*
|
|
4
|
+
* Fully independent: no DOMPurify, no block registry, no side effects.
|
|
5
|
+
* Just renderChart() + Chart.js lazy load.
|
|
6
|
+
*/
|
|
7
|
+
export type { ChartConfig, ChartOptions, DataSet, ChartInstance } from '../types.js';
|
|
8
|
+
import type { ChartConfig, ChartInstance } from '../types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Render a chart into a container element.
|
|
11
|
+
* Lazy-loads Chart.js on first call.
|
|
12
|
+
*/
|
|
13
|
+
export declare function renderChart(container: HTMLElement, config: ChartConfig): Promise<ChartInstance>;
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/chart/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAErF,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAU9D;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,WAAW,EACtB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,aAAa,CAAC,CAmExB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { renderChart } from './chunk-PBRPD4A5.js';
|
|
2
|
+
import { BaseRenderer } from './chunk-ODHF7VXV.js';
|
|
3
|
+
|
|
4
|
+
// src/renderers/chart.ts
|
|
5
|
+
var ChartRenderer = class extends BaseRenderer {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(...arguments);
|
|
8
|
+
this.chartInstance = null;
|
|
9
|
+
}
|
|
10
|
+
render(block, container) {
|
|
11
|
+
this.container = container;
|
|
12
|
+
const wrapper = document.createElement("div");
|
|
13
|
+
wrapper.className = "blex-chart";
|
|
14
|
+
wrapper.setAttribute("data-testid", `blex-chart-${block.id}`);
|
|
15
|
+
container.appendChild(wrapper);
|
|
16
|
+
renderChart(wrapper, block.data).then((instance) => {
|
|
17
|
+
this.chartInstance = instance;
|
|
18
|
+
container.setAttribute("data-blex-ready", "true");
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
update(block) {
|
|
22
|
+
if (this.chartInstance) {
|
|
23
|
+
this.chartInstance.update(block.data);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
destroy() {
|
|
27
|
+
this.chartInstance?.destroy();
|
|
28
|
+
this.chartInstance = null;
|
|
29
|
+
super.destroy();
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
function createChartRenderer() {
|
|
33
|
+
return new ChartRenderer();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { ChartRenderer, createChartRenderer };
|
|
37
|
+
//# sourceMappingURL=chart-2QT47W6E.js.map
|
|
38
|
+
//# sourceMappingURL=chart-2QT47W6E.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/renderers/chart.ts"],"names":[],"mappings":";;;;AAMO,IAAM,aAAA,GAAN,cAA4B,YAAA,CAA6B;AAAA,EAAzD,WAAA,GAAA;AAAA,IAAA,KAAA,CAAA,GAAA,SAAA,CAAA;AACL,IAAA,IAAA,CAAQ,aAAA,GAAsC,IAAA;AAAA,EAAA;AAAA,EAE9C,MAAA,CAAO,OAAqC,SAAA,EAA8B;AACxE,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AAEjB,IAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC5C,IAAA,OAAA,CAAQ,SAAA,GAAY,YAAA;AACpB,IAAA,OAAA,CAAQ,YAAA,CAAa,aAAA,EAAe,CAAA,WAAA,EAAc,KAAA,CAAM,EAAE,CAAA,CAAE,CAAA;AAC5D,IAAA,SAAA,CAAU,YAAY,OAAO,CAAA;AAE7B,IAAA,WAAA,CAAY,SAAS,KAAA,CAAM,IAAI,CAAA,CAAE,IAAA,CAAK,CAAC,QAAA,KAAa;AAClD,MAAA,IAAA,CAAK,aAAA,GAAgB,QAAA;AACrB,MAAA,SAAA,CAAU,YAAA,CAAa,mBAAmB,MAAM,CAAA;AAAA,IAClD,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,OAAO,KAAA,EAA2C;AAChD,IAAA,IAAI,KAAK,aAAA,EAAe;AACtB,MAAA,IAAA,CAAK,aAAA,CAAc,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,OAAA,GAAgB;AACd,IAAA,IAAA,CAAK,eAAe,OAAA,EAAQ;AAC5B,IAAA,IAAA,CAAK,aAAA,GAAgB,IAAA;AACrB,IAAA,KAAA,CAAM,OAAA,EAAQ;AAAA,EAChB;AACF;AAEO,SAAS,mBAAA,GAAqC;AACnD,EAAA,OAAO,IAAI,aAAA,EAAc;AAC3B","file":"chart-2QT47W6E.js","sourcesContent":["import { BaseRenderer } from '../base-renderer.js';\nimport type { ContentBlock, ChartConfig, ChartInstance } from '../types.js';\nimport { renderChart } from '../chart/index.js';\n\nexport interface ChartBlockData extends ChartConfig {}\n\nexport class ChartRenderer extends BaseRenderer<ChartBlockData> {\n private chartInstance: ChartInstance | null = null;\n\n render(block: ContentBlock<ChartBlockData>, container: HTMLElement): void {\n this.container = container;\n\n const wrapper = document.createElement('div');\n wrapper.className = 'blex-chart';\n wrapper.setAttribute('data-testid', `blex-chart-${block.id}`);\n container.appendChild(wrapper);\n\n renderChart(wrapper, block.data).then((instance) => {\n this.chartInstance = instance;\n container.setAttribute('data-blex-ready', 'true');\n });\n }\n\n update(block: ContentBlock<ChartBlockData>): void {\n if (this.chartInstance) {\n this.chartInstance.update(block.data);\n }\n }\n\n destroy(): void {\n this.chartInstance?.destroy();\n this.chartInstance = null;\n super.destroy();\n }\n}\n\nexport function createChartRenderer(): ChartRenderer {\n return new ChartRenderer();\n}\n"]}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// src/base-renderer.ts
|
|
2
|
+
var BaseRenderer = class {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.container = null;
|
|
5
|
+
this.interactionCallback = null;
|
|
6
|
+
this.trackedListeners = [];
|
|
7
|
+
this.trackedTimers = [];
|
|
8
|
+
this.trackedRAFs = [];
|
|
9
|
+
this.trackedObservers = [];
|
|
10
|
+
this.destroyed = false;
|
|
11
|
+
}
|
|
12
|
+
onInteraction(callback) {
|
|
13
|
+
this.interactionCallback = callback;
|
|
14
|
+
}
|
|
15
|
+
destroy() {
|
|
16
|
+
if (this.destroyed) return;
|
|
17
|
+
this.destroyed = true;
|
|
18
|
+
for (const { target, type, listener } of this.trackedListeners) {
|
|
19
|
+
target.removeEventListener(type, listener);
|
|
20
|
+
}
|
|
21
|
+
this.trackedListeners = [];
|
|
22
|
+
for (const id of this.trackedTimers) {
|
|
23
|
+
clearTimeout(id);
|
|
24
|
+
clearInterval(id);
|
|
25
|
+
}
|
|
26
|
+
this.trackedTimers = [];
|
|
27
|
+
for (const id of this.trackedRAFs) {
|
|
28
|
+
cancelAnimationFrame(id);
|
|
29
|
+
}
|
|
30
|
+
this.trackedRAFs = [];
|
|
31
|
+
for (const observer of this.trackedObservers) {
|
|
32
|
+
observer.disconnect();
|
|
33
|
+
}
|
|
34
|
+
this.trackedObservers = [];
|
|
35
|
+
if (this.container) {
|
|
36
|
+
this.container.innerHTML = "";
|
|
37
|
+
this.container = null;
|
|
38
|
+
}
|
|
39
|
+
this.interactionCallback = null;
|
|
40
|
+
}
|
|
41
|
+
// --- Tracked resource helpers ---
|
|
42
|
+
addListener(target, type, listener) {
|
|
43
|
+
target.addEventListener(type, listener);
|
|
44
|
+
this.trackedListeners.push({ target, type, listener });
|
|
45
|
+
}
|
|
46
|
+
setTimeout(fn, ms) {
|
|
47
|
+
const id = window.setTimeout(fn, ms);
|
|
48
|
+
this.trackedTimers.push(id);
|
|
49
|
+
return id;
|
|
50
|
+
}
|
|
51
|
+
setInterval(fn, ms) {
|
|
52
|
+
const id = window.setInterval(fn, ms);
|
|
53
|
+
this.trackedTimers.push(id);
|
|
54
|
+
return id;
|
|
55
|
+
}
|
|
56
|
+
requestAnimationFrame(fn) {
|
|
57
|
+
const id = window.requestAnimationFrame(fn);
|
|
58
|
+
this.trackedRAFs.push(id);
|
|
59
|
+
return id;
|
|
60
|
+
}
|
|
61
|
+
trackObserver(observer) {
|
|
62
|
+
this.trackedObservers.push(observer);
|
|
63
|
+
}
|
|
64
|
+
emit(interaction) {
|
|
65
|
+
this.interactionCallback?.(interaction);
|
|
66
|
+
}
|
|
67
|
+
get isDestroyed() {
|
|
68
|
+
return this.destroyed;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export { BaseRenderer };
|
|
73
|
+
//# sourceMappingURL=chunk-ODHF7VXV.js.map
|
|
74
|
+
//# sourceMappingURL=chunk-ODHF7VXV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/base-renderer.ts"],"names":[],"mappings":"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","file":"chunk-ODHF7VXV.js","sourcesContent":["import type { BlockRenderer, ContentBlock, BlockInteraction } from './types.js';\n\n/**\n * Abstract base class for block renderers. Tracks all resources\n * (event listeners, timers, RAF, observers) and releases them on destroy().\n *\n * All built-in renderers extend this class to guarantee zero leaks.\n */\nexport abstract class BaseRenderer<T = unknown> implements BlockRenderer<T> {\n protected container: HTMLElement | null = null;\n protected interactionCallback: ((interaction: BlockInteraction) => void) | null = null;\n\n private trackedListeners: Array<{ target: EventTarget; type: string; listener: EventListener }> = [];\n private trackedTimers: number[] = [];\n private trackedRAFs: number[] = [];\n private trackedObservers: Array<ResizeObserver | MutationObserver | IntersectionObserver> = [];\n private destroyed = false;\n\n abstract render(block: ContentBlock<T>, container: HTMLElement): void;\n\n update?(block: ContentBlock<T>): void;\n\n onInteraction(callback: (interaction: BlockInteraction) => void): void {\n this.interactionCallback = callback;\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n\n // Remove all tracked event listeners\n for (const { target, type, listener } of this.trackedListeners) {\n target.removeEventListener(type, listener);\n }\n this.trackedListeners = [];\n\n // Clear all tracked timers\n for (const id of this.trackedTimers) {\n clearTimeout(id);\n clearInterval(id);\n }\n this.trackedTimers = [];\n\n // Cancel all tracked animation frames\n for (const id of this.trackedRAFs) {\n cancelAnimationFrame(id);\n }\n this.trackedRAFs = [];\n\n // Disconnect all tracked observers\n for (const observer of this.trackedObservers) {\n observer.disconnect();\n }\n this.trackedObservers = [];\n\n // Clear DOM\n if (this.container) {\n this.container.innerHTML = '';\n this.container = null;\n }\n\n this.interactionCallback = null;\n }\n\n // --- Tracked resource helpers ---\n\n protected addListener(target: EventTarget, type: string, listener: EventListener): void {\n target.addEventListener(type, listener);\n this.trackedListeners.push({ target, type, listener });\n }\n\n protected setTimeout(fn: () => void, ms: number): number {\n const id = window.setTimeout(fn, ms);\n this.trackedTimers.push(id);\n return id;\n }\n\n protected setInterval(fn: () => void, ms: number): number {\n const id = window.setInterval(fn, ms);\n this.trackedTimers.push(id);\n return id;\n }\n\n protected requestAnimationFrame(fn: FrameRequestCallback): number {\n const id = window.requestAnimationFrame(fn);\n this.trackedRAFs.push(id);\n return id;\n }\n\n protected trackObserver(observer: ResizeObserver | MutationObserver | IntersectionObserver): void {\n this.trackedObservers.push(observer);\n }\n\n protected emit(interaction: BlockInteraction): void {\n this.interactionCallback?.(interaction);\n }\n\n protected get isDestroyed(): boolean {\n return this.destroyed;\n }\n}\n"]}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// src/chart/index.ts
|
|
2
|
+
var chartJsLoaded = null;
|
|
3
|
+
async function loadChartJs() {
|
|
4
|
+
if (chartJsLoaded) return chartJsLoaded;
|
|
5
|
+
chartJsLoaded = await import('chart.js');
|
|
6
|
+
return chartJsLoaded;
|
|
7
|
+
}
|
|
8
|
+
async function renderChart(container, config) {
|
|
9
|
+
const chartJs = await loadChartJs();
|
|
10
|
+
const {
|
|
11
|
+
Chart,
|
|
12
|
+
BarController,
|
|
13
|
+
LineController,
|
|
14
|
+
PieController,
|
|
15
|
+
DoughnutController,
|
|
16
|
+
CategoryScale,
|
|
17
|
+
LinearScale,
|
|
18
|
+
BarElement,
|
|
19
|
+
LineElement,
|
|
20
|
+
PointElement,
|
|
21
|
+
ArcElement,
|
|
22
|
+
Title,
|
|
23
|
+
Legend,
|
|
24
|
+
Tooltip
|
|
25
|
+
} = chartJs;
|
|
26
|
+
Chart.register(
|
|
27
|
+
BarController,
|
|
28
|
+
LineController,
|
|
29
|
+
PieController,
|
|
30
|
+
DoughnutController,
|
|
31
|
+
CategoryScale,
|
|
32
|
+
LinearScale,
|
|
33
|
+
BarElement,
|
|
34
|
+
LineElement,
|
|
35
|
+
PointElement,
|
|
36
|
+
ArcElement,
|
|
37
|
+
Title,
|
|
38
|
+
Legend,
|
|
39
|
+
Tooltip
|
|
40
|
+
);
|
|
41
|
+
const canvas = document.createElement("canvas");
|
|
42
|
+
canvas.setAttribute("data-testid", "blex-chart-canvas");
|
|
43
|
+
container.appendChild(canvas);
|
|
44
|
+
const chartInstance = new Chart(canvas, {
|
|
45
|
+
type: config.type,
|
|
46
|
+
data: {
|
|
47
|
+
labels: config.data.labels,
|
|
48
|
+
datasets: config.data.datasets.map((ds) => ({
|
|
49
|
+
label: ds.label,
|
|
50
|
+
data: ds.values,
|
|
51
|
+
backgroundColor: ds.color,
|
|
52
|
+
borderColor: ds.color
|
|
53
|
+
}))
|
|
54
|
+
},
|
|
55
|
+
options: {
|
|
56
|
+
responsive: config.options?.responsive ?? true,
|
|
57
|
+
plugins: {
|
|
58
|
+
title: config.options?.title ? { display: true, text: config.options.title } : { display: false },
|
|
59
|
+
legend: { display: config.options?.legend ?? true }
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
container.setAttribute("data-blex-ready", "true");
|
|
64
|
+
return {
|
|
65
|
+
update(partial) {
|
|
66
|
+
if (partial.data) {
|
|
67
|
+
chartInstance.data.labels = partial.data.labels ?? chartInstance.data.labels;
|
|
68
|
+
if (partial.data.datasets) {
|
|
69
|
+
chartInstance.data.datasets = partial.data.datasets.map((ds) => ({
|
|
70
|
+
label: ds.label,
|
|
71
|
+
data: ds.values,
|
|
72
|
+
backgroundColor: ds.color,
|
|
73
|
+
borderColor: ds.color
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (partial.options?.title) {
|
|
78
|
+
chartInstance.options.plugins.title = { display: true, text: partial.options.title };
|
|
79
|
+
}
|
|
80
|
+
chartInstance.update();
|
|
81
|
+
},
|
|
82
|
+
destroy() {
|
|
83
|
+
chartInstance.destroy();
|
|
84
|
+
canvas.remove();
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export { renderChart };
|
|
90
|
+
//# sourceMappingURL=chunk-PBRPD4A5.js.map
|
|
91
|
+
//# sourceMappingURL=chunk-PBRPD4A5.js.map
|