or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration-styling.mdcore-functionality.mddata-models.mdhook-system.mdindex.mdplugin-integration.md
tile.json

hook-system.mddocs/

0

# Hook System

1

2

Event-driven customization system for intercepting and modifying table rendering at various stages, enabling advanced customization and dynamic content generation.

3

4

## Capabilities

5

6

### Hook Data Classes

7

8

Base classes providing context information for hook functions.

9

10

#### HookData Class

11

12

Base hook data class providing table and document context.

13

14

```typescript { .api }

15

class HookData {

16

/** Reference to the table being rendered */

17

table: Table;

18

/** Current page number */

19

pageNumber: number;

20

/** Table settings */

21

settings: Settings;

22

/** jsPDF document instance */

23

doc: jsPDFDocument;

24

/** Current cursor position */

25

cursor: Pos | null;

26

27

constructor(doc: DocHandler, table: Table, cursor: Pos | null);

28

}

29

```

30

31

#### CellHookData Class

32

33

Extended hook data class for cell-specific events.

34

35

```typescript { .api }

36

class CellHookData extends HookData {

37

/** Reference to the current cell */

38

cell: Cell;

39

/** Reference to the current row */

40

row: Row;

41

/** Reference to the current column */

42

column: Column;

43

/** Section type: 'head', 'body', or 'foot' */

44

section: "head" | "body" | "foot";

45

46

constructor(

47

doc: DocHandler,

48

table: Table,

49

cell: Cell,

50

row: Row,

51

column: Column,

52

cursor: Pos | null

53

);

54

}

55

```

56

57

### Hook Function Types

58

59

Function signatures for different hook events.

60

61

```typescript { .api }

62

/** Page-level hook function */

63

type PageHook = (data: HookData) => void | boolean;

64

65

/** Cell-level hook function */

66

type CellHook = (data: CellHookData) => void | boolean;

67

```

68

69

### Hook Events

70

71

Available hook events for customizing table rendering behavior.

72

73

#### didParseCell Hook

74

75

Called after the plugin has finished parsing cell content. Use this to override content or styles for specific cells.

76

77

```typescript { .api }

78

/** Called when the plugin finished parsing cell content */

79

didParseCell?: CellHook;

80

```

81

82

**Usage Example:**

83

84

```typescript

85

autoTable(doc, {

86

head: [['Name', 'Amount', 'Status']],

87

body: [

88

['John Doe', '1500', 'active'],

89

['Jane Smith', '2300', 'inactive'],

90

],

91

didParseCell: (data) => {

92

const { cell, column } = data;

93

94

// Format currency

95

if (column.dataKey === 1) { // Amount column

96

const amount = parseFloat(cell.text[0]);

97

cell.text = [`$${amount.toLocaleString()}`];

98

}

99

100

// Style status column

101

if (column.dataKey === 2) { // Status column

102

if (cell.text[0] === 'active') {

103

cell.styles.textColor = [0, 128, 0];

104

cell.text = ['✓ Active'];

105

} else {

106

cell.styles.textColor = [128, 0, 0];

107

cell.text = ['✗ Inactive'];

108

}

109

}

110

},

111

});

112

```

113

114

#### willDrawCell Hook

115

116

Called before a cell is drawn. Use this to modify styling or positioning before rendering.

117

118

```typescript { .api }

119

/** Called before a cell or row is drawn */

120

willDrawCell?: CellHook;

121

```

122

123

**Usage Example:**

124

125

```typescript

126

autoTable(doc, {

127

head: [['Product', 'Stock', 'Price']],

128

body: [

129

['Laptop', '5', '999'],

130

['Phone', '0', '599'],

131

['Tablet', '12', '399'],

132

],

133

willDrawCell: (data) => {

134

const { cell, column, doc } = data;

135

136

// Highlight low stock items

137

if (column.dataKey === 1) { // Stock column

138

const stock = parseInt(cell.text[0]);

139

if (stock === 0) {

140

cell.styles.fillColor = [255, 200, 200]; // Light red

141

cell.styles.fontStyle = 'bold';

142

} else if (stock < 10) {

143

cell.styles.fillColor = [255, 255, 200]; // Light yellow

144

}

145

}

146

147

// Apply custom jsPDF styling

148

if (column.dataKey === 2) { // Price column

149

doc.setTextColor(0, 100, 0); // Dark green for prices

150

}

151

},

152

});

153

```

154

155

#### didDrawCell Hook

156

157

Called after a cell has been drawn. Use this to add additional content like images, shapes, or custom text.

158

159

```typescript { .api }

160

/** Called after a cell has been added to the page */

161

didDrawCell?: CellHook;

162

```

163

164

**Usage Example:**

165

166

```typescript

167

autoTable(doc, {

168

head: [['Name', 'Rating', 'Notes']],

169

body: [

170

['Product A', '5', 'Excellent quality'],

171

['Product B', '3', 'Average'],

172

['Product C', '4', 'Good value'],

173

],

174

didDrawCell: (data) => {

175

const { cell, column, doc } = data;

176

177

// Draw star ratings

178

if (column.dataKey === 1) { // Rating column

179

const rating = parseInt(cell.text[0]);

180

const startX = cell.x + 5;

181

const centerY = cell.y + cell.height / 2;

182

183

// Draw stars

184

for (let i = 0; i < 5; i++) {

185

const x = startX + (i * 10);

186

if (i < rating) {

187

doc.setFillColor(255, 215, 0); // Gold

188

doc.circle(x, centerY, 3, 'F');

189

} else {

190

doc.setDrawColor(200, 200, 200);

191

doc.circle(x, centerY, 3, 'S');

192

}

193

}

194

}

195

196

// Add custom borders

197

if (column.dataKey === 2) { // Notes column

198

doc.setDrawColor(100, 100, 100);

199

doc.setLineWidth(0.5);

200

doc.line(cell.x, cell.y, cell.x + cell.width, cell.y);

201

}

202

},

203

});

204

```

205

206

#### willDrawPage Hook

207

208

Called before starting to draw content on a page. Use this to add headers, watermarks, or page setup.

209

210

```typescript { .api }

211

/** Called before starting to draw on a page */

212

willDrawPage?: PageHook;

213

```

214

215

**Usage Example:**

216

217

```typescript

218

autoTable(doc, {

219

head: [['Item', 'Quantity', 'Price']],

220

body: largeDataSet,

221

willDrawPage: (data) => {

222

const { doc, table, pageNumber } = data;

223

224

// Add header to each page

225

doc.setFontSize(16);

226

doc.setFont('helvetica', 'bold');

227

doc.text('Sales Report', 20, 20);

228

229

// Add page number

230

doc.setFontSize(10);

231

doc.setFont('helvetica', 'normal');

232

doc.text(`Page ${pageNumber}`, 200, 20);

233

234

// Add watermark

235

doc.setTextColor(200, 200, 200);

236

doc.setFontSize(48);

237

doc.text('DRAFT', 105, 150, {

238

angle: 45,

239

align: 'center'

240

});

241

242

// Reset text color for table content

243

doc.setTextColor(0, 0, 0);

244

doc.setFontSize(10);

245

},

246

});

247

```

248

249

#### didDrawPage Hook

250

251

Called after the plugin has finished drawing everything on a page. Use this to add footers, signatures, or final page elements.

252

253

```typescript { .api }

254

/** Called after the plugin has finished drawing everything on a page */

255

didDrawPage?: PageHook;

256

```

257

258

**Usage Example:**

259

260

```typescript

261

autoTable(doc, {

262

head: [['Description', 'Amount']],

263

body: invoiceItems,

264

didDrawPage: (data) => {

265

const { doc, table, pageNumber, cursor } = data;

266

267

// Add footer

268

const pageHeight = doc.internal.pageSize.height;

269

const pageWidth = doc.internal.pageSize.width;

270

271

doc.setFontSize(8);

272

doc.setTextColor(100, 100, 100);

273

274

// Company information

275

doc.text('MyCompany Inc.', 20, pageHeight - 20);

276

doc.text('123 Business St, City, State 12345', 20, pageHeight - 15);

277

doc.text('Phone: (555) 123-4567', 20, pageHeight - 10);

278

279

// Page number and date

280

doc.text(`Page ${pageNumber}`, pageWidth - 50, pageHeight - 20);

281

doc.text(new Date().toLocaleDateString(), pageWidth - 50, pageHeight - 15);

282

283

// Add total on last page

284

if (cursor && cursor.y > pageHeight - 100) {

285

const totalY = cursor.y + 10;

286

doc.setFontSize(12);

287

doc.setFont('helvetica', 'bold');

288

doc.text('Total: $1,234.56', pageWidth - 80, totalY);

289

}

290

},

291

});

292

```

293

294

### Hook Properties Interface

295

296

Collection of all hook functions for a table.

297

298

```typescript { .api }

299

interface HookProps {

300

didParseCell: CellHook[];

301

willDrawCell: CellHook[];

302

didDrawCell: CellHook[];

303

willDrawPage: PageHook[];

304

didDrawPage: PageHook[];

305

}

306

```

307

308

### Advanced Hook Patterns

309

310

#### Conditional Content Modification

311

312

```typescript

313

const didParseCell = (data: CellHookData) => {

314

const { cell, column, row, section } = data;

315

316

// Only modify body cells

317

if (section !== 'body') return;

318

319

// Format dates in specific column

320

if (column.dataKey === 'date') {

321

const date = new Date(cell.text[0]);

322

cell.text = [date.toLocaleDateString()];

323

}

324

325

// Add row numbers

326

if (column.index === 0) {

327

cell.text = [`${row.index + 1}. ${cell.text[0]}`];

328

}

329

};

330

```

331

332

#### Dynamic Styling Based on Data

333

334

```typescript

335

const willDrawCell = (data: CellHookData) => {

336

const { cell, row, table } = data;

337

338

// Alternate row colors differently for each section

339

switch (data.section) {

340

case 'head':

341

cell.styles.fillColor = [52, 73, 94];

342

cell.styles.textColor = [255, 255, 255];

343

break;

344

345

case 'body':

346

if (row.index % 2 === 0) {

347

cell.styles.fillColor = [245, 245, 245];

348

}

349

break;

350

351

case 'foot':

352

cell.styles.fillColor = [52, 152, 219];

353

cell.styles.textColor = [255, 255, 255];

354

cell.styles.fontStyle = 'bold';

355

break;

356

}

357

};

358

```

359

360

#### Multi-Page Headers and Footers

361

362

```typescript

363

let pageCount = 0;

364

365

const willDrawPage = (data: HookData) => {

366

pageCount++;

367

const { doc } = data;

368

369

// Different header for first page

370

if (pageCount === 1) {

371

doc.setFontSize(20);

372

doc.text('Annual Report 2024', 20, 30);

373

doc.setFontSize(12);

374

doc.text('Confidential Document', 20, 40);

375

} else {

376

doc.setFontSize(12);

377

doc.text('Annual Report 2024 (Continued)', 20, 20);

378

}

379

};

380

381

const didDrawPage = (data: HookData) => {

382

const { doc, pageNumber } = data;

383

const pageHeight = doc.internal.pageSize.height;

384

385

// Page footer with different content for last page

386

if (pageNumber === pageCount) {

387

doc.text('End of Report', 20, pageHeight - 10);

388

} else {

389

doc.text('Continued on next page...', 20, pageHeight - 10);

390

}

391

};

392

```

393

394

#### Hook Return Values

395

396

Hooks can return `false` to prevent default behavior:

397

398

```typescript

399

const willDrawCell = (data: CellHookData) => {

400

const { cell, column } = data;

401

402

// Skip drawing empty cells

403

if (!cell.text[0] || cell.text[0].trim() === '') {

404

return false; // Prevents cell from being drawn

405

}

406

407

// Skip drawing specific columns

408

if (column.dataKey === 'internal_id') {

409

return false;

410

}

411

};

412

```

413

414

### Position and Cursor Information

415

416

```typescript { .api }

417

type Pos = { x: number; y: number };

418

```

419

420

Hook functions receive cursor position information for precise element placement:

421

422

```typescript

423

const didDrawCell = (data: CellHookData) => {

424

const { cell, doc, cursor } = data;

425

426

console.log(`Cell position: (${cell.x}, ${cell.y})`);

427

console.log(`Cell size: ${cell.width} x ${cell.height}`);

428

console.log(`Cursor position: (${cursor?.x}, ${cursor?.y})`);

429

430

// Use position for custom drawing

431

doc.circle(cell.x + cell.width - 5, cell.y + 5, 2, 'F');

432

};

433

```