or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

form-validation.mdhttp-client.mdindex.mdsearch-data.mdstorage-state.mdui-interactions.mdvisual-effects.md

visual-effects.mddocs/

0

# Visual Effects and Progress

1

2

Drawing, progress indication, and QR code generation for enhanced user experience and visual feedback.

3

4

## Capabilities

5

6

### useDrauu

7

8

Interactive drawing and sketching using drauu library with canvas integration.

9

10

```typescript { .api }

11

/**

12

* Interactive drawing and sketching with canvas integration

13

* @param target - Target element (canvas or container) for drawing

14

* @param options - Drawing configuration options

15

* @returns Drawing control interface and event handlers

16

*/

17

function useDrauu(

18

target: MaybeComputedElementRef,

19

options?: UseDrauuOptions

20

): UseDrauuReturn;

21

22

interface UseDrauuReturn {

23

/** The drauu instance for direct access */

24

drauuInstance: Ref<Drauu | undefined>;

25

/** Load SVG drawing data */

26

load: (svg: string) => void;

27

/** Export current drawing as SVG string */

28

dump: () => string | undefined;

29

/** Clear all drawings */

30

clear: () => void;

31

/** Cancel current drawing operation */

32

cancel: () => void;

33

/** Undo last drawing action */

34

undo: () => boolean | undefined;

35

/** Redo previously undone action */

36

redo: () => boolean | undefined;

37

/** Whether undo is available */

38

canUndo: ShallowRef<boolean>;

39

/** Whether redo is available */

40

canRedo: ShallowRef<boolean>;

41

/** Current brush configuration */

42

brush: Ref<Brush>;

43

/** Drawing state change events */

44

onChanged: EventHookOn;

45

/** Drawing commit events */

46

onCommitted: EventHookOn;

47

/** Drawing start events */

48

onStart: EventHookOn;

49

/** Drawing end events */

50

onEnd: EventHookOn;

51

/** Drawing cancel events */

52

onCanceled: EventHookOn;

53

}

54

55

type UseDrauuOptions = Omit<Options, 'el'>;

56

57

// drauu library types

58

interface Options {

59

brush?: Brush;

60

acceptsInputTypes?: InputType[];

61

coordinate?: CoordinateType;

62

coordinateScale?: number | false;

63

coordinateTransform?: boolean | CoordinateTransform;

64

}

65

66

interface Brush {

67

mode?: DrawingMode;

68

color?: string;

69

size?: number;

70

cornerRadius?: number;

71

dasharray?: string | undefined;

72

arrowEnd?: boolean;

73

arrowStart?: boolean;

74

}

75

76

type DrawingMode = 'draw' | 'line' | 'rectangle' | 'ellipse' | 'stylus';

77

type InputType = 'mouse' | 'touch' | 'pen';

78

type CoordinateType = 'relative' | 'absolute';

79

```

80

81

**Usage Examples:**

82

83

```typescript

84

import { useDrauu } from "@vueuse/integrations/useDrauu";

85

import { ref, onMounted } from 'vue';

86

87

// Basic drawing setup

88

const canvasRef = ref<HTMLCanvasElement>();

89

const {

90

drauuInstance,

91

brush,

92

clear,

93

undo,

94

redo,

95

canUndo,

96

canRedo,

97

dump,

98

load,

99

onChanged

100

} = useDrauu(canvasRef, {

101

brush: {

102

mode: 'draw',

103

color: '#000000',

104

size: 3

105

}

106

});

107

108

// Change brush settings

109

const changeBrushColor = (color: string) => {

110

brush.value.color = color;

111

};

112

113

const changeBrushSize = (size: number) => {

114

brush.value.size = size;

115

};

116

117

const changeBrushMode = (mode: DrawingMode) => {

118

brush.value.mode = mode;

119

};

120

121

// Drawing tools

122

const clearCanvas = () => clear();

123

const undoLastAction = () => undo();

124

const redoAction = () => redo();

125

126

// Save and load drawings

127

const saveDrawing = () => {

128

const svgData = dump();

129

if (svgData) {

130

localStorage.setItem('saved-drawing', svgData);

131

}

132

};

133

134

const loadDrawing = () => {

135

const svgData = localStorage.getItem('saved-drawing');

136

if (svgData) {

137

load(svgData);

138

}

139

};

140

141

// Listen to drawing changes

142

onChanged(() => {

143

console.log('Drawing changed');

144

// Auto-save or validation logic

145

});

146

147

// Advanced brush configuration

148

const setupAdvancedBrush = () => {

149

brush.value = {

150

mode: 'line',

151

color: '#ff0000',

152

size: 5,

153

dasharray: '5,5', // Dashed line

154

arrowEnd: true, // Arrow at end

155

cornerRadius: 2 // Rounded corners

156

};

157

};

158

159

// Multiple drawing modes

160

const drawingModes = [

161

{ name: 'Pen', mode: 'draw' },

162

{ name: 'Line', mode: 'line' },

163

{ name: 'Rectangle', mode: 'rectangle' },

164

{ name: 'Ellipse', mode: 'ellipse' },

165

{ name: 'Stylus', mode: 'stylus' }

166

];

167

```

168

169

### useNProgress

170

171

Progress bar indication using NProgress library with reactive state management.

172

173

```typescript { .api }

174

/**

175

* Progress bar indication with reactive state management

176

* @param currentProgress - Current progress value (0-1 or null)

177

* @param options - NProgress configuration options

178

* @returns Progress control interface

179

*/

180

function useNProgress(

181

currentProgress?: MaybeRefOrGetter<number | null | undefined>,

182

options?: UseNProgressOptions

183

): {

184

/** Whether progress bar is currently showing */

185

isLoading: WritableComputedRef<boolean>;

186

/** Current progress value */

187

progress: Ref<number | null | undefined>;

188

/** Start progress indication */

189

start: () => NProgress;

190

/** Complete progress and hide bar */

191

done: (force?: boolean) => NProgress;

192

/** Remove progress bar from DOM */

193

remove: () => void;

194

};

195

196

type UseNProgressOptions = Partial<NProgressOptions>;

197

198

// NProgress configuration options

199

interface NProgressOptions {

200

/** Minimum progress value */

201

minimum?: number;

202

/** Animation template */

203

template?: string;

204

/** Easing function */

205

easing?: string;

206

/** Animation speed */

207

speed?: number;

208

/** Trickle animation */

209

trickle?: boolean;

210

/** Trickle speed */

211

trickleSpeed?: number;

212

/** Show spinner */

213

showSpinner?: boolean;

214

/** Barber pole moving animation */

215

barberPole?: boolean;

216

/** Parent element selector */

217

parent?: string;

218

}

219

```

220

221

**Usage Examples:**

222

223

```typescript

224

import { useNProgress } from "@vueuse/integrations/useNProgress";

225

import { ref } from 'vue';

226

227

// Basic progress indication

228

const { isLoading, start, done } = useNProgress();

229

230

// Show progress during async operations

231

const fetchData = async () => {

232

start();

233

try {

234

const response = await fetch('/api/data');

235

const data = await response.json();

236

return data;

237

} finally {

238

done();

239

}

240

};

241

242

// Controlled progress

243

const uploadProgress = ref(0);

244

const { progress, isLoading } = useNProgress(uploadProgress, {

245

minimum: 0.1,

246

speed: 200,

247

showSpinner: false

248

});

249

250

const simulateUpload = () => {

251

uploadProgress.value = 0;

252

const interval = setInterval(() => {

253

uploadProgress.value += 0.1;

254

if (uploadProgress.value >= 1) {

255

clearInterval(interval);

256

uploadProgress.value = null; // Hide progress bar

257

}

258

}, 100);

259

};

260

261

// Router integration

262

import { useRoute } from 'vue-router';

263

264

const route = useRoute();

265

const { start, done } = useNProgress();

266

267

// Show progress on route changes

268

watch(() => route.path, () => {

269

start();

270

nextTick(() => done());

271

});

272

273

// Custom configuration

274

const { start, done } = useNProgress(undefined, {

275

minimum: 0.2,

276

easing: 'ease',

277

speed: 500,

278

trickle: true,

279

trickleSpeed: 200,

280

showSpinner: true,

281

barberPole: true,

282

template: '<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'

283

});

284

285

// Global loading state

286

const globalLoading = ref(false);

287

const { isLoading: nprogress } = useNProgress();

288

289

// Sync with global state

290

watch(globalLoading, (loading) => {

291

nprogress.value = loading;

292

});

293

```

294

295

### useQRCode

296

297

QR code generation using qrcode library with reactive updates.

298

299

```typescript { .api }

300

/**

301

* QR code generation with reactive updates

302

* @param text - Text content to encode in QR code

303

* @param options - QR code generation options

304

* @returns Reactive data URL for QR code image

305

*/

306

function useQRCode(

307

text: MaybeRefOrGetter<string>,

308

options?: QRCode.QRCodeToDataURLOptions

309

): ShallowRef<string>;

310

311

// QR code generation options

312

namespace QRCode {

313

interface QRCodeToDataURLOptions {

314

/** Error correction level */

315

errorCorrectionLevel?: 'low' | 'medium' | 'quartile' | 'high';

316

/** QR code type (auto-detected if not specified) */

317

type?: 'image/png' | 'image/jpeg' | 'image/webp';

318

/** Rendered image quality (0.0 to 1.0) */

319

quality?: number;

320

/** Margin around QR code in modules */

321

margin?: number;

322

/** Scale factor for image size */

323

scale?: number;

324

/** Image width in pixels (overrides scale) */

325

width?: number;

326

/** Color options */

327

color?: {

328

/** Dark color (foreground) */

329

dark?: string;

330

/** Light color (background) */

331

light?: string;

332

};

333

}

334

}

335

```

336

337

**Usage Examples:**

338

339

```typescript

340

import { useQRCode } from "@vueuse/integrations/useQRCode";

341

import { ref, computed } from 'vue';

342

343

// Basic QR code generation

344

const text = ref('https://example.com');

345

const qrCode = useQRCode(text);

346

347

// QR code will be a data URL string like:

348

// "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAK..."

349

350

// Dynamic QR code

351

const userInput = ref('');

352

const qrCodeUrl = useQRCode(userInput, {

353

width: 200,

354

margin: 2,

355

color: {

356

dark: '#000000',

357

light: '#FFFFFF'

358

}

359

});

360

361

// Contact information QR code

362

const contactInfo = computed(() => {

363

return [

364

'BEGIN:VCARD',

365

'VERSION:3.0',

366

'FN:John Doe',

367

'TEL:+1234567890',

368

'EMAIL:john@example.com',

369

'URL:https://johndoe.com',

370

'END:VCARD'

371

].join('\n');

372

});

373

374

const contactQR = useQRCode(contactInfo, {

375

errorCorrectionLevel: 'medium',

376

width: 300

377

});

378

379

// WiFi QR code

380

const wifiConfig = computed(() => {

381

const ssid = 'MyWiFi';

382

const password = 'MyPassword';

383

const security = 'WPA';

384

return `WIFI:T:${security};S:${ssid};P:${password};;`;

385

});

386

387

const wifiQR = useQRCode(wifiConfig);

388

389

// Custom styling options

390

const styledQR = useQRCode('Custom styled QR code', {

391

width: 250,

392

margin: 3,

393

color: {

394

dark: '#1a365d', // Dark blue

395

light: '#f7fafc' // Light gray

396

},

397

errorCorrectionLevel: 'high'

398

});

399

400

// Multiple QR codes with different options

401

const qrCodes = [

402

{

403

name: 'Website',

404

text: ref('https://example.com'),

405

options: { width: 150, color: { dark: '#2563eb' } }

406

},

407

{

408

name: 'Email',

409

text: ref('mailto:contact@example.com'),

410

options: { width: 150, color: { dark: '#dc2626' } }

411

},

412

{

413

name: 'Phone',

414

text: ref('tel:+1234567890'),

415

options: { width: 150, color: { dark: '#059669' } }

416

}

417

].map(item => ({

418

...item,

419

qrCode: useQRCode(item.text, item.options)

420

}));

421

422

// Download QR code

423

const downloadQRCode = (dataUrl: string, filename: string) => {

424

const link = document.createElement('a');

425

link.download = filename;

426

link.href = dataUrl;

427

link.click();

428

};

429

```

430

431

**Template Usage Examples:**

432

433

```vue

434

<template>

435

<div class="qr-code-examples">

436

<!-- Basic QR code display -->

437

<div>

438

<h3>Website QR Code</h3>

439

<img :src="qrCode" alt="QR Code" />

440

</div>

441

442

<!-- Dynamic QR code generator -->

443

<div>

444

<h3>Generate QR Code</h3>

445

<input v-model="userInput" placeholder="Enter text or URL" />

446

<div v-if="userInput">

447

<img :src="qrCodeUrl" alt="Generated QR Code" />

448

<button @click="downloadQRCode(qrCodeUrl, 'qrcode.png')">

449

Download QR Code

450

</button>

451

</div>

452

</div>

453

454

<!-- Multiple QR codes -->

455

<div class="qr-grid">

456

<div v-for="item in qrCodes" :key="item.name" class="qr-item">

457

<h4>{{ item.name }}</h4>

458

<img :src="item.qrCode" :alt="`${item.name} QR Code`" />

459

</div>

460

</div>

461

</div>

462

</template>

463

464

<style>

465

.qr-code-examples {

466

display: flex;

467

flex-direction: column;

468

gap: 20px;

469

}

470

471

.qr-grid {

472

display: grid;

473

grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));

474

gap: 16px;

475

}

476

477

.qr-item {

478

text-align: center;

479

padding: 16px;

480

border: 1px solid #e2e8f0;

481

border-radius: 8px;

482

}

483

484

.qr-item img {

485

max-width: 100%;

486

height: auto;

487

}

488

</style>

489

```