or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

component-api.mdfunctional-api.mdindex.mdmenu-bar.mdthemes.md
tile.json

component-api.mddocs/

0

# Component API

1

2

The component API provides Vue components for declarative context menu construction. This approach integrates seamlessly with Vue templates and is ideal for static menus, form-based interfaces, and component-driven architectures.

3

4

## Capabilities

5

6

### ContextMenu Component

7

8

Main context menu container component that manages menu display, positioning, and lifecycle.

9

10

```typescript { .api }

11

declare component ContextMenu {

12

props: {

13

/** Menu configuration options */

14

options: MenuOptions;

15

/** Show/hide menu state */

16

show: boolean;

17

};

18

emits: {

19

/** Emitted when show state should change */

20

'update:show': (show: boolean) => boolean;

21

/** Emitted when menu closes */

22

'close': () => boolean;

23

};

24

slots: {

25

/** Default slot for menu items */

26

default: {};

27

/** Custom item renderer slot */

28

itemRender: {

29

label: string;

30

icon: string;

31

disabled: boolean;

32

onClick: (e: MouseEvent) => void;

33

onMouseEnter: (e: MouseEvent) => void;

34

};

35

/** Custom separator renderer slot */

36

separatorRender: {};

37

/** Custom icon renderer slot */

38

itemIconRender: { label: string; icon: string; };

39

/** Custom label renderer slot */

40

itemLabelRender: { label: string; };

41

/** Custom shortcut renderer slot */

42

itemShortcutRender: { shortcut: string; };

43

/** Custom right arrow renderer slot */

44

itemRightArrowRender: {};

45

/** Custom check mark renderer slot */

46

itemCheckRender: { checked: boolean; };

47

};

48

}

49

```

50

51

**Usage Examples:**

52

53

```vue

54

<template>

55

<!-- Basic component usage -->

56

<div @contextmenu="onRightClick">

57

<context-menu v-model:show="showMenu" :options="menuOptions">

58

<context-menu-item label="Copy" icon="copy" @click="handleCopy" />

59

<context-menu-item label="Paste" icon="paste" @click="handlePaste" />

60

<context-menu-separator />

61

<context-menu-item label="Delete" icon="delete" @click="handleDelete" />

62

</context-menu>

63

</div>

64

65

<!-- Advanced usage with nested menus -->

66

<div @contextmenu="onAdvancedRightClick">

67

<context-menu

68

v-model:show="showAdvancedMenu"

69

:options="advancedOptions"

70

@close="onMenuClose"

71

>

72

<context-menu-item label="File Operations" icon="folder">

73

<template #submenu="{ show }">

74

<context-menu-group v-if="show" label="File">

75

<context-menu-item label="New" shortcut="Ctrl+N" @click="createNew" />

76

<context-menu-item label="Open" shortcut="Ctrl+O" @click="openFile" />

77

<context-menu-separator />

78

<context-menu-item label="Save" shortcut="Ctrl+S" @click="saveFile" />

79

</context-menu-group>

80

</template>

81

</context-menu-item>

82

83

<context-menu-item label="Edit" :disabled="!canEdit" @click="editItem" />

84

</context-menu>

85

</div>

86

87

<!-- Custom rendering with slots -->

88

<context-menu v-model:show="showCustomMenu" :options="customOptions">

89

<template #itemRender="{ label, icon, onClick, onMouseEnter, disabled }">

90

<div

91

:class="['custom-menu-item', { disabled }]"

92

@click="onClick"

93

@mouseenter="onMouseEnter"

94

>

95

<img v-if="icon" :src="icon" class="custom-icon" />

96

<span class="custom-label">{{ label }}</span>

97

</div>

98

</template>

99

100

<context-menu-item label="Custom Item" icon="/icons/custom.png" />

101

</context-menu>

102

</template>

103

104

<script setup>

105

import { ref } from 'vue';

106

107

const showMenu = ref(false);

108

const menuOptions = ref({

109

x: 0,

110

y: 0,

111

theme: 'default',

112

zIndex: 1000

113

});

114

115

function onRightClick(e) {

116

e.preventDefault();

117

menuOptions.value.x = e.clientX;

118

menuOptions.value.y = e.clientY;

119

showMenu.value = true;

120

}

121

122

function onMenuClose() {

123

console.log('Menu closed');

124

}

125

</script>

126

```

127

128

### ContextMenuItem Component

129

130

Individual menu item component with support for icons, labels, shortcuts, and click handling.

131

132

```typescript { .api }

133

declare component ContextMenuItem {

134

props: {

135

/** Menu item label text, VNode, or render function */

136

label?: string | VNode | ((label: string) => VNode);

137

/** Icon CSS class, VNode, or render function */

138

icon?: string | VNode | ((icon: string) => VNode);

139

/** Custom icon font class name */

140

iconFontClass?: string;

141

/** SVG symbol icon reference */

142

svgIcon?: string;

143

/** SVG element properties */

144

svgProps?: SVGAttributes;

145

/** Disable the menu item */

146

disabled?: boolean;

147

/** Hide the menu item */

148

hidden?: boolean;

149

/** Show check mark */

150

checked?: boolean;

151

/** Shortcut key display text */

152

shortcut?: string;

153

/** Reserve icon width space */

154

preserveIconWidth?: boolean;

155

/** Custom CSS class */

156

customClass?: string;

157

/** Custom render function */

158

customRender?: VNode | ((item: MenuItem) => VNode);

159

/** Click handler function */

160

clickHandler?: (e: MouseEvent | KeyboardEvent) => void;

161

/** Show right arrow indicator for submenus */

162

showRightArrow?: boolean;

163

/** Indicates if item has children/submenu */

164

hasChildren?: boolean;

165

/** Should close menu when this item is clicked */

166

clickClose?: boolean;

167

/** Allow click event when item has children */

168

clickableWhenHasChildren?: boolean;

169

/** Raw MenuItem data object */

170

rawMenuItem?: MenuItem;

171

};

172

emits: {

173

/** Emitted when item is clicked */

174

'click': (e: MouseEvent | KeyboardEvent) => boolean;

175

/** Emitted when submenu opens */

176

'subMenuOpen': () => boolean;

177

/** Emitted when submenu closes */

178

'subMenuClose': () => boolean;

179

};

180

slots: {

181

/** Default slot content */

182

default: {};

183

/** Icon slot */

184

icon: {};

185

/** Label slot */

186

label: {};

187

/** Shortcut slot */

188

shortcut: {};

189

/** Right arrow slot for submenus */

190

rightArrow: {};

191

/** Check mark slot */

192

check: {};

193

/** Submenu slot */

194

submenu: { context: MenuItemContext; show: boolean; };

195

};

196

}

197

```

198

199

**Usage Examples:**

200

201

```vue

202

<template>

203

<!-- Basic menu items -->

204

<context-menu-item label="Simple Item" @click="handleClick" />

205

206

<!-- Item with icon and shortcut -->

207

<context-menu-item

208

label="Save File"

209

icon="save-icon"

210

shortcut="Ctrl+S"

211

@click="saveFile"

212

/>

213

214

<!-- Disabled and checked items -->

215

<context-menu-item

216

label="Readonly Mode"

217

:disabled="!canEdit"

218

:checked="isReadonly"

219

@click="toggleReadonly"

220

/>

221

222

<!-- Item with custom icon slot -->

223

<context-menu-item label="Custom Icon" @click="handleCustom">

224

<template #icon>

225

<svg class="custom-svg-icon">

226

<use xlink:href="#my-icon"></use>

227

</svg>

228

</template>

229

</context-menu-item>

230

231

<!-- Item with submenu -->

232

<context-menu-item label="Recent Files">

233

<template #submenu="{ show, context }">

234

<context-menu-group v-if="show" label="Recent">

235

<context-menu-item

236

v-for="file in recentFiles"

237

:key="file.id"

238

:label="file.name"

239

@click="() => openFile(file)"

240

/>

241

</context-menu-group>

242

</template>

243

</context-menu-item>

244

245

<!-- Item with custom rendering -->

246

<context-menu-item

247

label="Custom Render"

248

:custom-render="customItemRenderer"

249

@click="handleCustomRender"

250

/>

251

</template>

252

253

<script setup>

254

import { h } from 'vue';

255

256

function customItemRenderer(item) {

257

return h('div', { class: 'custom-item-wrapper' }, [

258

h('span', { class: 'custom-prefix' }, '★'),

259

h('span', item.label),

260

h('span', { class: 'custom-suffix' }, '→')

261

]);

262

}

263

</script>

264

```

265

266

### ContextMenuSeparator Component

267

268

Visual separator component for grouping related menu items.

269

270

```typescript { .api }

271

declare component ContextMenuSeparator {

272

// No props or events

273

}

274

```

275

276

**Usage:**

277

278

```vue

279

<template>

280

<context-menu>

281

<context-menu-item label="Copy" @click="copy" />

282

<context-menu-item label="Paste" @click="paste" />

283

284

<!-- Visual separator -->

285

<context-menu-separator />

286

287

<context-menu-item label="Delete" @click="delete" />

288

</context-menu>

289

</template>

290

```

291

292

### ContextMenuGroup Component

293

294

Container component for creating nested submenus with optional group labels.

295

296

```typescript { .api }

297

declare component ContextMenuGroup {

298

props: {

299

/** Group label text */

300

label?: string;

301

/** Icon CSS class or image path */

302

icon?: string;

303

/** Custom icon font class name */

304

iconFontClass?: string;

305

/** SVG symbol icon reference */

306

svgIcon?: string;

307

/** SVG element properties */

308

svgProps?: SVGAttributes;

309

/** Disable the group */

310

disabled?: boolean;

311

/** Hide the group */

312

hidden?: boolean;

313

/** Show check mark */

314

checked?: boolean;

315

/** Shortcut key display text */

316

shortcut?: string;

317

/** Reserve fixed-width icon area */

318

preserveIconWidth?: boolean;

319

/** Show right arrow indicator */

320

showRightArrow?: boolean;

321

/** Close menu when group is clicked */

322

clickClose?: boolean;

323

/** Adjust submenu position */

324

adjustSubMenuPosition?: boolean;

325

/** Maximum height of submenu */

326

maxHeight?: number | string;

327

/** Maximum width of submenu */

328

maxWidth?: number | string;

329

/** Minimum width of submenu */

330

minWidth?: number | string;

331

/** Custom CSS class */

332

customClass?: string;

333

/** Click handler function */

334

clickHandler?: () => void;

335

};

336

slots: {

337

/** Default slot for child menu items */

338

default: {};

339

};

340

}

341

```

342

343

**Usage Examples:**

344

345

```vue

346

<template>

347

<!-- Basic group with label -->

348

<context-menu-group label="File Operations">

349

<context-menu-item label="New" @click="createNew" />

350

<context-menu-item label="Open" @click="openFile" />

351

<context-menu-item label="Save" @click="saveFile" />

352

</context-menu-group>

353

354

<!-- Nested groups -->

355

<context-menu-group label="Edit">

356

<context-menu-item label="Undo" @click="undo" />

357

<context-menu-item label="Redo" @click="redo" />

358

359

<context-menu-group label="Selection">

360

<context-menu-item label="Select All" @click="selectAll" />

361

<context-menu-item label="Select None" @click="selectNone" />

362

<context-menu-item label="Invert Selection" @click="invertSelection" />

363

</context-menu-group>

364

</context-menu-group>

365

366

<!-- Dynamic group content -->

367

<context-menu-group label="Recent Projects">

368

<context-menu-item

369

v-for="project in recentProjects"

370

:key="project.id"

371

:label="project.name"

372

:icon="project.icon"

373

@click="() => openProject(project)"

374

/>

375

<context-menu-separator v-if="recentProjects.length > 0" />

376

<context-menu-item label="Clear Recent" @click="clearRecent" />

377

</context-menu-group>

378

</template>

379

```

380

381

## Component Integration Patterns

382

383

### Reactive Menu State

384

385

```vue

386

<template>

387

<div class="editor" @contextmenu="showContextMenu">

388

<context-menu v-model:show="menuVisible" :options="menuConfig">

389

<context-menu-item

390

label="Cut"

391

:disabled="!hasSelection"

392

shortcut="Ctrl+X"

393

@click="cutText"

394

/>

395

<context-menu-item

396

label="Copy"

397

:disabled="!hasSelection"

398

shortcut="Ctrl+C"

399

@click="copyText"

400

/>

401

<context-menu-item

402

label="Paste"

403

:disabled="!canPaste"

404

shortcut="Ctrl+V"

405

@click="pasteText"

406

/>

407

<context-menu-separator />

408

<context-menu-item

409

label="Select All"

410

shortcut="Ctrl+A"

411

@click="selectAllText"

412

/>

413

</context-menu>

414

</div>

415

</template>

416

417

<script setup>

418

import { ref, computed } from 'vue';

419

420

const menuVisible = ref(false);

421

const selectedText = ref('');

422

const clipboard = ref('');

423

424

const menuConfig = ref({

425

x: 0,

426

y: 0,

427

theme: 'default'

428

});

429

430

const hasSelection = computed(() => selectedText.value.length > 0);

431

const canPaste = computed(() => clipboard.value.length > 0);

432

433

function showContextMenu(e) {

434

e.preventDefault();

435

menuConfig.value.x = e.clientX;

436

menuConfig.value.y = e.clientY;

437

menuVisible.value = true;

438

}

439

</script>

440

```

441

442

### Menu with Form Integration

443

444

```vue

445

<template>

446

<form @submit="submitForm">

447

<input

448

v-model="formData.name"

449

@contextmenu="showFieldMenu"

450

data-field="name"

451

/>

452

453

<context-menu v-model:show="fieldMenuVisible" :options="fieldMenuConfig">

454

<context-menu-item label="Clear Field" @click="clearCurrentField" />

455

<context-menu-item label="Reset to Default" @click="resetCurrentField" />

456

<context-menu-separator />

457

<context-menu-item label="Validate Field" @click="validateCurrentField" />

458

<context-menu-group label="Auto-fill">

459

<context-menu-item

460

v-for="suggestion in currentFieldSuggestions"

461

:key="suggestion"

462

:label="suggestion"

463

@click="() => setFieldValue(suggestion)"

464

/>

465

</context-menu-group>

466

</context-menu>

467

</form>

468

</template>

469

470

<script setup>

471

import { ref, computed } from 'vue';

472

473

const fieldMenuVisible = ref(false);

474

const currentField = ref('');

475

const formData = ref({ name: '', email: '' });

476

477

const currentFieldSuggestions = computed(() => {

478

if (currentField.value === 'name') {

479

return ['John Doe', 'Jane Smith', 'Admin User'];

480

}

481

return [];

482

});

483

484

function showFieldMenu(e) {

485

e.preventDefault();

486

currentField.value = e.target.dataset.field;

487

fieldMenuConfig.value.x = e.clientX;

488

fieldMenuConfig.value.y = e.clientY;

489

fieldMenuVisible.value = true;

490

}

491

</script>

492

```

493

494

## Component Reference Interface

495

496

When using template refs with context menu components:

497

498

```typescript { .api }

499

interface ContextMenuComponentRef extends ContextMenuInstance {

500

/** Close the menu */

501

closeMenu(): void;

502

/** Check if menu is closed */

503

isClosed(): boolean;

504

/** Get menu reference for advanced control */

505

getMenuRef(): ContextSubMenuInstance | undefined;

506

/** Get menu dimensions */

507

getMenuDimensions(): { width: number, height: number };

508

}

509

510

interface ContextMenuGroupRef {

511

/** Get submenu instance */

512

getSubMenuRef(): ContextSubMenuInstance;

513

/** Get menu item reference */

514

getMenuItemRef(): ContextSubMenuInstance;

515

}

516

```

517

518

**Usage with Template Refs:**

519

520

```vue

521

<template>

522

<context-menu ref="menuRef" v-model:show="show" :options="options">

523

<!-- menu items -->

524

</context-menu>

525

526

<button @click="controlMenu">Control Menu</button>

527

</template>

528

529

<script setup>

530

import { ref } from 'vue';

531

532

const menuRef = ref<ContextMenuComponentRef>();

533

534

function controlMenu() {

535

if (menuRef.value) {

536

if (menuRef.value.isClosed()) {

537

// Menu is closed, could trigger show

538

} else {

539

// Menu is open, close it

540

menuRef.value.closeMenu();

541

}

542

}

543

}

544

</script>

545

```