or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

code-transformation.mdcontext-integration.mdindex.mdlive-components.mdstandalone-editor.md

context-integration.mddocs/

0

# Context Integration

1

2

React Context and Higher-Order Component utilities for integrating with the live editing system. These tools allow you to build custom components that interact with the live editing state and create advanced integrations.

3

4

## Capabilities

5

6

### LiveContext

7

8

React Context that provides access to the live editing state and control functions. This context is used internally by all live components and can be consumed by custom components to access editing state.

9

10

```typescript { .api }

11

/**

12

* React Context providing live editing state and controls

13

*/

14

const LiveContext: React.Context<{

15

/** Current error message from compilation or execution */

16

error?: string;

17

/** Currently rendered React component from code execution */

18

element?: ComponentType | null;

19

/** Original code string passed to LiveProvider */

20

code: string;

21

/** Most recent code change (may differ from 'code' during editing) */

22

newCode?: string;

23

/** Whether editing is currently disabled */

24

disabled: boolean;

25

/** Language identifier for syntax highlighting */

26

language: string;

27

/** Prism theme for syntax highlighting */

28

theme?: typeof themes.nightOwl;

29

/** Function to handle and display errors */

30

onError(error: Error): void;

31

/** Function called when code content changes */

32

onChange(value: string): void;

33

}>;

34

```

35

36

**Usage Examples:**

37

38

```typescript

39

import React, { useContext } from "react";

40

import { LiveProvider, LiveContext } from "react-live";

41

42

// Custom component consuming LiveContext

43

function CodeStats() {

44

const { code, error, element } = useContext(LiveContext);

45

46

return (

47

<div className="code-stats">

48

<p>Lines: {code.split('\n').length}</p>

49

<p>Characters: {code.length}</p>

50

<p>Status: {error ? 'Error' : element ? 'Valid' : 'Empty'}</p>

51

{error && <p className="error">Error: {error}</p>}

52

</div>

53

);

54

}

55

56

// Usage within LiveProvider

57

function PlaygroundWithStats() {

58

return (

59

<LiveProvider code="<h1>Hello World</h1>">

60

<div className="editor-panel">

61

<LiveEditor />

62

<CodeStats />

63

</div>

64

<LivePreview />

65

</LiveProvider>

66

);

67

}

68

69

// Custom reset button

70

function ResetButton({ defaultCode }: { defaultCode: string }) {

71

const { onChange } = useContext(LiveContext);

72

73

return (

74

<button onClick={() => onChange(defaultCode)}>

75

Reset Code

76

</button>

77

);

78

}

79

80

// Code formatter component

81

function FormatButton() {

82

const { code, onChange } = useContext(LiveContext);

83

84

const formatCode = () => {

85

try {

86

// Simple formatter (in real app, use prettier or similar)

87

const formatted = code

88

.split('\n')

89

.map(line => line.trim())

90

.join('\n');

91

onChange(formatted);

92

} catch (error) {

93

console.error('Format failed:', error);

94

}

95

};

96

97

return (

98

<button onClick={formatCode}>

99

Format Code

100

</button>

101

);

102

}

103

104

// Custom error display with details

105

function DetailedError() {

106

const { error, code } = useContext(LiveContext);

107

108

if (!error) return null;

109

110

const getErrorDetails = (error: string) => {

111

if (error.includes('SyntaxError')) {

112

return 'Check for missing brackets, quotes, or semicolons';

113

}

114

if (error.includes('ReferenceError')) {

115

return 'Variable or component not found in scope';

116

}

117

return 'Unexpected error occurred';

118

};

119

120

return (

121

<div className="detailed-error">

122

<h4>Error Details</h4>

123

<pre className="error-message">{error}</pre>

124

<p className="error-hint">{getErrorDetails(error)}</p>

125

<details>

126

<summary>Code Context</summary>

127

<pre>{code}</pre>

128

</details>

129

</div>

130

);

131

}

132

133

// Complete custom playground

134

function CustomPlayground() {

135

const initialCode = `

136

function Welcome({ name }) {

137

return <h1>Hello, {name}!</h1>;

138

}

139

140

<Welcome name="React Live" />

141

`;

142

143

return (

144

<LiveProvider code={initialCode} noInline>

145

<div className="playground-layout">

146

<div className="editor-section">

147

<div className="editor-header">

148

<CodeStats />

149

<ResetButton defaultCode={initialCode} />

150

<FormatButton />

151

</div>

152

<LiveEditor />

153

</div>

154

<div className="preview-section">

155

<LivePreview />

156

<DetailedError />

157

</div>

158

</div>

159

</LiveProvider>

160

);

161

}

162

```

163

164

### withLive

165

166

Higher-Order Component that injects the entire LiveContext as props into a wrapped component. Useful for class components or when you need to pass live state as props.

167

168

```typescript { .api }

169

/**

170

* Higher-Order Component that injects live context as props

171

* @param WrappedComponent - Component to receive live context as props

172

* @returns Enhanced component with live context injected as 'live' prop

173

*/

174

function withLive<T>(

175

WrappedComponent: ComponentType<T & { live: Record<string, unknown> }>

176

): ComponentType<T>;

177

```

178

179

**Usage Examples:**

180

181

```typescript

182

import React, { Component } from "react";

183

import { LiveProvider, withLive } from "react-live";

184

185

// Class component with live context

186

class CodeAnalyzer extends Component<{ live: any }> {

187

analyzeProp() {

188

const { live } = this.props;

189

return {

190

hasError: !!live.error,

191

codeLength: live.code.length,

192

lineCount: live.code.split('\n').length,

193

isDisabled: live.disabled

194

};

195

}

196

197

render() {

198

const analysis = this.analyzeProp();

199

const { live } = this.props;

200

201

return (

202

<div className="code-analyzer">

203

<h3>Code Analysis</h3>

204

<ul>

205

<li>Status: {analysis.hasError ? 'Error' : 'Valid'}</li>

206

<li>Length: {analysis.codeLength} characters</li>

207

<li>Lines: {analysis.lineCount}</li>

208

<li>Editable: {analysis.isDisabled ? 'No' : 'Yes'}</li>

209

</ul>

210

{live.error && (

211

<div className="error-section">

212

<strong>Error:</strong> {live.error}

213

</div>

214

)}

215

</div>

216

);

217

}

218

}

219

220

// Enhance with live context

221

const EnhancedCodeAnalyzer = withLive(CodeAnalyzer);

222

223

// Function component with live context as props

224

function CodeToolbar({ live, onSave }: { live: any; onSave: (code: string) => void }) {

225

const handleSave = () => {

226

if (!live.error && live.code.trim()) {

227

onSave(live.code);

228

}

229

};

230

231

const handleClear = () => {

232

live.onChange('');

233

};

234

235

return (

236

<div className="code-toolbar">

237

<button

238

onClick={handleSave}

239

disabled={!!live.error || !live.code.trim()}

240

>

241

Save Code

242

</button>

243

<button onClick={handleClear}>

244

Clear

245

</button>

246

<span className="status">

247

{live.error ? '❌ Error' : '✅ Valid'}

248

</span>

249

</div>

250

);

251

}

252

253

const EnhancedCodeToolbar = withLive(CodeToolbar);

254

255

// Usage in application

256

function AppWithLiveComponents() {

257

const [savedCodes, setSavedCodes] = useState<string[]>([]);

258

259

const handleSave = (code: string) => {

260

setSavedCodes(prev => [...prev, code]);

261

};

262

263

return (

264

<div className="app">

265

<LiveProvider code="<h1>Start coding...</h1>">

266

<div className="main-editor">

267

<EnhancedCodeToolbar onSave={handleSave} />

268

<LiveEditor />

269

<EnhancedCodeAnalyzer />

270

</div>

271

<div className="preview-area">

272

<LivePreview />

273

<LiveError />

274

</div>

275

</LiveProvider>

276

277

<div className="saved-codes">

278

<h3>Saved Codes ({savedCodes.length})</h3>

279

{savedCodes.map((code, index) => (

280

<details key={index}>

281

<summary>Code #{index + 1}</summary>

282

<pre>{code}</pre>

283

</details>

284

))}

285

</div>

286

</div>

287

);

288

}

289

290

// Custom hook alternative to withLive HOC

291

function useLiveContext() {

292

const context = useContext(LiveContext);

293

if (!context) {

294

throw new Error('useLiveContext must be used within a LiveProvider');

295

}

296

return context;

297

}

298

299

// Usage with custom hook

300

function ModernCodeAnalyzer() {

301

const live = useLiveContext();

302

303

const stats = useMemo(() => ({

304

words: live.code.split(/\s+/).filter(Boolean).length,

305

jsx: live.code.includes('<') && live.code.includes('>'),

306

typescript: live.code.includes(':') && live.enableTypeScript,

307

hasHooks: /use[A-Z]/.test(live.code)

308

}), [live.code]);

309

310

return (

311

<div className="modern-analyzer">

312

<h4>Code Statistics</h4>

313

<div className="stats-grid">

314

<div>Words: {stats.words}</div>

315

<div>JSX: {stats.jsx ? '✓' : '✗'}</div>

316

<div>TypeScript: {stats.typescript ? '✓' : '✗'}</div>

317

<div>Hooks: {stats.hasHooks ? '✓' : '✗'}</div>

318

</div>

319

</div>

320

);

321

}

322

```

323

324

## Advanced Integration Patterns

325

326

### State Synchronization

327

328

```typescript

329

// Synchronize external state with live context

330

function useSyncedLiveCode(externalCode: string) {

331

const { code, onChange } = useContext(LiveContext);

332

333

useEffect(() => {

334

if (code !== externalCode) {

335

onChange(externalCode);

336

}

337

}, [externalCode, code, onChange]);

338

339

return { code, onChange };

340

}

341

342

// Bidirectional sync

343

function useBidirectionalSync(

344

externalCode: string,

345

onExternalChange: (code: string) => void

346

) {

347

const { code, onChange } = useContext(LiveContext);

348

349

// Sync external -> live

350

useEffect(() => {

351

if (code !== externalCode) {

352

onChange(externalCode);

353

}

354

}, [externalCode]);

355

356

// Sync live -> external (debounced)

357

useEffect(() => {

358

const timer = setTimeout(() => {

359

if (code !== externalCode) {

360

onExternalChange(code);

361

}

362

}, 1000);

363

364

return () => clearTimeout(timer);

365

}, [code, externalCode, onExternalChange]);

366

}

367

```

368

369

### Error Recovery

370

371

```typescript

372

function AutoRecoveringEditor() {

373

const { code, error, onChange } = useContext(LiveContext);

374

const [lastValidCode, setLastValidCode] = useState(code);

375

376

useEffect(() => {

377

if (!error && code.trim()) {

378

setLastValidCode(code);

379

}

380

}, [code, error]);

381

382

const recoverToLastValid = () => {

383

onChange(lastValidCode);

384

};

385

386

return (

387

<div className="recovering-editor">

388

<LiveEditor />

389

{error && (

390

<div className="error-recovery">

391

<p>Error detected: {error}</p>

392

<button onClick={recoverToLastValid}>

393

Recover to Last Valid Code

394

</button>

395

</div>

396

)}

397

</div>

398

);

399

}

400

```

401

402

### Performance Optimization

403

404

```typescript

405

// Memoized context consumer

406

const MemoizedCodeDisplay = React.memo(() => {

407

const { code, error } = useContext(LiveContext);

408

409

return (

410

<div className="code-display">

411

<pre>{code}</pre>

412

{error && <div className="error">{error}</div>}

413

</div>

414

);

415

});

416

417

// Debounced change handler

418

function useDebouncedLiveChange(delay = 300) {

419

const { onChange } = useContext(LiveContext);

420

const debouncedOnChange = useMemo(

421

() => debounce(onChange, delay),

422

[onChange, delay]

423

);

424

425

return debouncedOnChange;

426

}

427

```