or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

extensions.mdindex.mdinitialization.mdinstance-methods.mdjquery.mdoptions.mdstatic-methods.md

extensions.mddocs/

0

# Extensions

1

2

OverlayScrollbars provides a powerful extension system that allows you to add custom functionality to instances through a plugin architecture. Extensions can be registered globally and used across multiple instances.

3

4

## Extension System Overview

5

6

Extensions are objects with lifecycle methods that get called when they are added to or removed from an OverlayScrollbars instance. They provide a clean way to extend functionality without modifying the core library.

7

8

## Extension Registration

9

10

### Global Registration

11

12

```javascript { .api }

13

OverlayScrollbars.extension(

14

name: string,

15

extensionConstructor: ExtensionConstructor,

16

defaultOptions?: object

17

): boolean;

18

```

19

20

Register an extension globally so it can be used by any instance.

21

22

```javascript

23

// Register a simple logging extension

24

OverlayScrollbars.extension('logger', function(instance, options) {

25

return {

26

added: function() {

27

if (options.logInit) {

28

console.log('Logger extension added to instance');

29

}

30

},

31

32

removed: function() {

33

if (options.logDestroy) {

34

console.log('Logger extension removed from instance');

35

}

36

}

37

};

38

}, {

39

// Default extension options

40

logInit: true,

41

logDestroy: true,

42

logScroll: false

43

});

44

```

45

46

## Extension Usage

47

48

### Adding Extensions to Instances

49

50

Extensions can be added during initialization or dynamically after creation.

51

52

```javascript

53

// Add extension during initialization

54

const instance = OverlayScrollbars(element, {}, {

55

logger: {

56

logInit: true,

57

logScroll: true

58

}

59

});

60

61

// Add extension after initialization

62

instance.addExt('logger', {

63

logInit: false,

64

logDestroy: true

65

});

66

```

67

68

### Instance Extension Methods

69

70

```javascript { .api }

71

interface OverlayScrollbarsInstance {

72

addExt(extensionName: string, extensionOptions?: object): OverlayScrollbarsExtension | undefined;

73

removeExt(extensionName: string): boolean;

74

ext(extensionName: string): OverlayScrollbarsExtension | undefined;

75

}

76

```

77

78

```javascript

79

// Add extension to instance

80

const extensionInstance = instance.addExt('customExtension', {

81

option1: 'value1'

82

});

83

84

// Get extension instance

85

const ext = instance.ext('customExtension');

86

87

// Remove extension from instance

88

const removed = instance.removeExt('customExtension');

89

```

90

91

## Extension Examples

92

93

### Auto-Scroll Extension

94

95

```javascript

96

OverlayScrollbars.extension('autoScroll', function(instance, options) {

97

let intervalId;

98

let isScrolling = false;

99

100

const startAutoScroll = () => {

101

if (options.enabled && !isScrolling) {

102

isScrolling = true;

103

intervalId = setInterval(() => {

104

const state = instance.getState();

105

if (state.destroyed) {

106

stopAutoScroll();

107

return;

108

}

109

110

const currentY = state.contentScrollSize.height *

111

(instance.getElements('viewport').scrollTop /

112

(state.contentScrollSize.height - state.viewportSize.height));

113

114

const newY = currentY + options.speed;

115

const maxY = state.contentScrollSize.height - state.viewportSize.height;

116

117

if (newY >= maxY && options.loop) {

118

instance.scroll({ y: 0 }, options.resetDuration);

119

} else if (newY < maxY) {

120

instance.scroll({ y: newY });

121

} else {

122

stopAutoScroll();

123

}

124

}, options.interval);

125

}

126

};

127

128

const stopAutoScroll = () => {

129

if (intervalId) {

130

clearInterval(intervalId);

131

intervalId = null;

132

isScrolling = false;

133

}

134

};

135

136

return {

137

added: function() {

138

if (options.autoStart) {

139

startAutoScroll();

140

}

141

142

// Add public methods to instance

143

this.start = startAutoScroll;

144

this.stop = stopAutoScroll;

145

this.toggle = () => isScrolling ? stopAutoScroll() : startAutoScroll();

146

},

147

148

removed: function() {

149

stopAutoScroll();

150

}

151

};

152

}, {

153

enabled: true,

154

autoStart: false,

155

speed: 1,

156

interval: 50,

157

loop: true,

158

resetDuration: 1000

159

});

160

161

// Usage

162

const instance = OverlayScrollbars(element, {}, {

163

autoScroll: {

164

autoStart: true,

165

speed: 2,

166

loop: false

167

}

168

});

169

170

// Control auto-scroll

171

const autoScrollExt = instance.ext('autoScroll');

172

autoScrollExt.stop();

173

autoScrollExt.start();

174

```

175

176

### Scroll Position Tracker Extension

177

178

```javascript

179

OverlayScrollbars.extension('positionTracker', function(instance, options) {

180

let positions = [];

181

let currentIndex = -1;

182

183

const savePosition = () => {

184

const viewport = instance.getElements('viewport');

185

const position = {

186

x: viewport.scrollLeft,

187

y: viewport.scrollTop,

188

timestamp: Date.now()

189

};

190

191

positions.push(position);

192

currentIndex = positions.length - 1;

193

194

// Limit history size

195

if (positions.length > options.maxHistory) {

196

positions = positions.slice(-options.maxHistory);

197

currentIndex = positions.length - 1;

198

}

199

200

if (options.onPositionSaved) {

201

options.onPositionSaved(position, positions.length);

202

}

203

};

204

205

const goToPosition = (index) => {

206

if (index >= 0 && index < positions.length) {

207

const position = positions[index];

208

instance.scroll({ x: position.x, y: position.y }, options.scrollDuration);

209

currentIndex = index;

210

return position;

211

}

212

return null;

213

};

214

215

return {

216

added: function() {

217

// Save initial position

218

if (options.saveInitial) {

219

savePosition();

220

}

221

222

// Set up scroll tracking

223

if (options.trackScroll) {

224

instance.options('callbacks.onScrollStop', savePosition);

225

}

226

227

// Public API

228

this.save = savePosition;

229

this.goTo = goToPosition;

230

this.getHistory = () => [...positions];

231

this.clear = () => {

232

positions = [];

233

currentIndex = -1;

234

};

235

this.back = () => goToPosition(Math.max(0, currentIndex - 1));

236

this.forward = () => goToPosition(Math.min(positions.length - 1, currentIndex + 1));

237

},

238

239

removed: function() {

240

// Cleanup if needed

241

}

242

};

243

}, {

244

maxHistory: 20,

245

saveInitial: true,

246

trackScroll: true,

247

scrollDuration: 300,

248

onPositionSaved: null

249

});

250

251

// Usage

252

const instance = OverlayScrollbars(element, {}, {

253

positionTracker: {

254

maxHistory: 50,

255

onPositionSaved: (position, count) => {

256

console.log(`Position ${count} saved:`, position);

257

}

258

}

259

});

260

261

// Use the tracker

262

const tracker = instance.ext('positionTracker');

263

tracker.save(); // Manually save current position

264

tracker.back(); // Go to previous position

265

tracker.forward(); // Go to next position

266

console.log(tracker.getHistory()); // Get all saved positions

267

```

268

269

### Scroll Synchronization Extension

270

271

```javascript

272

OverlayScrollbars.extension('syncScroll', function(instance, options) {

273

let syncGroup = options.group || 'default';

274

let isUpdating = false;

275

276

// Global registry for sync groups

277

if (!window.OverlayScrollbarsSyncGroups) {

278

window.OverlayScrollbarsSyncGroups = {};

279

}

280

281

const registry = window.OverlayScrollbarsSyncGroups;

282

283

const onScroll = () => {

284

if (isUpdating) return;

285

286

const viewport = instance.getElements('viewport');

287

const scrollInfo = {

288

x: viewport.scrollLeft,

289

y: viewport.scrollTop,

290

xPercent: viewport.scrollLeft / (viewport.scrollWidth - viewport.clientWidth),

291

yPercent: viewport.scrollTop / (viewport.scrollHeight - viewport.clientHeight)

292

};

293

294

// Update other instances in the same group

295

if (registry[syncGroup]) {

296

registry[syncGroup].forEach(otherInstance => {

297

if (otherInstance !== instance) {

298

otherInstance._syncUpdate = true;

299

300

if (options.syncMode === 'percent') {

301

const otherViewport = otherInstance.getElements('viewport');

302

const targetX = scrollInfo.xPercent * (otherViewport.scrollWidth - otherViewport.clientWidth);

303

const targetY = scrollInfo.yPercent * (otherViewport.scrollHeight - otherViewport.clientHeight);

304

otherInstance.scroll({ x: targetX, y: targetY });

305

} else {

306

otherInstance.scroll({ x: scrollInfo.x, y: scrollInfo.y });

307

}

308

309

setTimeout(() => {

310

otherInstance._syncUpdate = false;

311

}, 10);

312

}

313

});

314

}

315

};

316

317

return {

318

added: function() {

319

// Add to sync group

320

if (!registry[syncGroup]) {

321

registry[syncGroup] = [];

322

}

323

registry[syncGroup].push(instance);

324

325

// Set up scroll listener

326

instance.options('callbacks.onScroll', onScroll);

327

},

328

329

removed: function() {

330

// Remove from sync group

331

if (registry[syncGroup]) {

332

const index = registry[syncGroup].indexOf(instance);

333

if (index > -1) {

334

registry[syncGroup].splice(index, 1);

335

}

336

337

// Clean up empty groups

338

if (registry[syncGroup].length === 0) {

339

delete registry[syncGroup];

340

}

341

}

342

}

343

};

344

}, {

345

group: 'default',

346

syncMode: 'percent' // 'percent' or 'absolute'

347

});

348

349

// Usage - synchronize scrolling between multiple elements

350

const instance1 = OverlayScrollbars(element1, {}, {

351

syncScroll: { group: 'mainContent' }

352

});

353

354

const instance2 = OverlayScrollbars(element2, {}, {

355

syncScroll: { group: 'mainContent' }

356

});

357

358

// Now scrolling one will scroll the other

359

```

360

361

## Extension Management

362

363

### Retrieving Extensions

364

365

```javascript

366

// Get all registered extensions

367

const allExtensions = OverlayScrollbars.extension();

368

369

// Get specific extension constructor

370

const loggerExt = OverlayScrollbars.extension('logger');

371

372

// Check if extension exists

373

if (OverlayScrollbars.extension('customExt')) {

374

// Extension is registered

375

}

376

```

377

378

### Unregistering Extensions

379

380

```javascript

381

// Unregister an extension

382

const success = OverlayScrollbars.extension('extensionName', null);

383

```

384

385

## Extension Lifecycle

386

387

```javascript { .api }

388

interface OverlayScrollbarsExtension {

389

added(instance: OverlayScrollbarsInstance, options: object): void;

390

removed?(): void;

391

}

392

393

type ExtensionConstructor = (

394

instance: OverlayScrollbarsInstance,

395

options: object

396

) => OverlayScrollbarsExtension;

397

```

398

399

### Extension Methods

400

401

- **added()** - Called when the extension is added to an instance

402

- **removed()** - Called when the extension is removed (optional)

403

404

### Extension Context

405

406

Inside extension methods, `this` refers to the extension instance, allowing you to store state and expose public methods.

407

408

```javascript

409

OverlayScrollbars.extension('statefulExtension', function(instance, options) {

410

let state = { count: 0 };

411

412

return {

413

added: function() {

414

// `this` is the extension instance

415

this.increment = () => state.count++;

416

this.getCount = () => state.count;

417

this.reset = () => state.count = 0;

418

},

419

420

removed: function() {

421

// Cleanup

422

}

423

};

424

});

425

426

// Access extension methods

427

const ext = instance.ext('statefulExtension');

428

ext.increment();

429

console.log(ext.getCount()); // 1

430

```

431

432

## Types

433

434

```javascript { .api }

435

interface OverlayScrollbarsExtension {

436

added(instance: OverlayScrollbarsInstance, options: object): void;

437

removed?(): void;

438

[key: string]: any; // Extensions can add custom methods

439

}

440

441

type ExtensionConstructor = (

442

instance: OverlayScrollbarsInstance,

443

options: object

444

) => OverlayScrollbarsExtension;

445

446

type OverlayScrollbarsExtensions = {

447

[extensionName: string]: object;

448

} | object[];

449

```