Skip to content

Commit c9af7f1

Browse files
Merge pull request #4 from SyntropyLabs/example-app
feat: add basic-demo example application
2 parents 67a2ad5 + 371a1bd commit c9af7f1

File tree

12 files changed

+261
-3
lines changed

12 files changed

+261
-3
lines changed

examples/basic-demo/.gitignore

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?
25+
26+
# Yarn lock (use parent's lock)
27+
yarn.lock

examples/basic-demo/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Basic Demo
2+
3+
A minimal example demonstrating `@syntropy-labs/react-web-speech`.
4+
5+
## Setup
6+
7+
```bash
8+
# From the root of the repository
9+
cd examples/basic-demo
10+
yarn install
11+
yarn dev
12+
```
13+
14+
## Features Demonstrated
15+
16+
- `useSpeechInputWithCursor` hook
17+
- Cursor-aware text insertion
18+
- Silence timeout
19+
- Permission state handling
20+
- Start/Stop toggling
21+
22+
## Note
23+
24+
This example uses `link:../..` to reference the local package. The parent package must be built first:
25+
26+
```bash
27+
# From root
28+
yarn build
29+
30+
# Then run the example
31+
cd examples/basic-demo
32+
yarn dev
33+
```
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import js from '@eslint/js'
2+
import globals from 'globals'
3+
import reactHooks from 'eslint-plugin-react-hooks'
4+
import reactRefresh from 'eslint-plugin-react-refresh'
5+
import tseslint from 'typescript-eslint'
6+
import { defineConfig, globalIgnores } from 'eslint/config'
7+
8+
export default defineConfig([
9+
globalIgnores(['dist']),
10+
{
11+
files: ['**/*.{ts,tsx}'],
12+
extends: [
13+
js.configs.recommended,
14+
tseslint.configs.recommended,
15+
reactHooks.configs.flat.recommended,
16+
reactRefresh.configs.vite,
17+
],
18+
languageOptions: {
19+
ecmaVersion: 2020,
20+
globals: globals.browser,
21+
},
22+
},
23+
])

examples/basic-demo/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>test-speech-app</title>
7+
</head>
8+
<body>
9+
<div id="root"></div>
10+
<script type="module" src="/src/main.tsx"></script>
11+
</body>
12+
</html>

examples/basic-demo/package.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"name": "basic-demo",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "tsc -b && vite build",
9+
"lint": "eslint .",
10+
"preview": "vite preview"
11+
},
12+
"dependencies": {
13+
"@syntropy-labs/react-web-speech": "link:../..",
14+
"react": "^19.2.0",
15+
"react-dom": "^19.2.0"
16+
},
17+
"devDependencies": {
18+
"@eslint/js": "^9.39.1",
19+
"@types/node": "^24.10.1",
20+
"@types/react": "^19.2.5",
21+
"@types/react-dom": "^19.2.3",
22+
"@vitejs/plugin-react": "^5.1.1",
23+
"eslint": "^9.39.1",
24+
"eslint-plugin-react-hooks": "^7.0.1",
25+
"eslint-plugin-react-refresh": "^0.4.24",
26+
"globals": "^16.5.0",
27+
"typescript": "~5.9.3",
28+
"typescript-eslint": "^8.46.4",
29+
"vite": "npm:rolldown-vite@7.2.5"
30+
},
31+
"resolutions": {
32+
"vite": "npm:rolldown-vite@7.2.5"
33+
}
34+
}

examples/basic-demo/src/App.tsx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { useRef, useState } from 'react'
2+
import { useSpeechInputWithCursor } from '@syntropy-labs/react-web-speech'
3+
4+
function App() {
5+
const [value, setValue] = useState('')
6+
const inputRef = useRef<HTMLTextAreaElement>(null)
7+
8+
const { isListening, isSupported, permissionState, toggle, transcript, error } =
9+
useSpeechInputWithCursor({
10+
inputRef,
11+
value,
12+
onChange: setValue,
13+
appendSpace: true,
14+
silenceTimeout: 3000,
15+
})
16+
17+
return (
18+
<div style={{ padding: '2rem', maxWidth: '600px', margin: '0 auto' }}>
19+
<h1>🎙️ Speech Input Test</h1>
20+
21+
<p>Supported: {isSupported ? '✅' : '❌'}</p>
22+
<p>Permission: {permissionState}</p>
23+
<p>Listening: {isListening ? '🔴 Yes' : '⚪ No'}</p>
24+
{error && <p style={{ color: 'red' }}>Error: {error.message}</p>}
25+
26+
<textarea
27+
ref={inputRef}
28+
value={value}
29+
onChange={(e) => setValue(e.target.value)}
30+
placeholder="Click the button and speak..."
31+
style={{ width: '100%', height: '150px', marginTop: '1rem' }}
32+
/>
33+
34+
<button
35+
onClick={toggle}
36+
style={{ marginTop: '1rem', padding: '0.5rem 1rem', cursor: 'pointer' }}
37+
>
38+
{isListening ? '🔴 Stop' : '🎙️ Start Speaking'}
39+
</button>
40+
41+
<p>
42+
<strong>Transcript:</strong> {transcript}
43+
</p>
44+
</div>
45+
)
46+
}
47+
48+
export default App

examples/basic-demo/src/main.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { StrictMode } from 'react'
2+
import { createRoot } from 'react-dom/client'
3+
import App from './App.tsx'
4+
5+
createRoot(document.getElementById('root')!).render(
6+
<StrictMode>
7+
<App />
8+
</StrictMode>
9+
)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"compilerOptions": {
3+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4+
"target": "ES2022",
5+
"useDefineForClassFields": true,
6+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
7+
"module": "ESNext",
8+
"types": ["vite/client"],
9+
"skipLibCheck": true,
10+
11+
/* Bundler mode */
12+
"moduleResolution": "bundler",
13+
"allowImportingTsExtensions": true,
14+
"verbatimModuleSyntax": true,
15+
"moduleDetection": "force",
16+
"noEmit": true,
17+
"jsx": "react-jsx",
18+
19+
/* Linting */
20+
"strict": true,
21+
"noUnusedLocals": true,
22+
"noUnusedParameters": true,
23+
"erasableSyntaxOnly": true,
24+
"noFallthroughCasesInSwitch": true,
25+
"noUncheckedSideEffectImports": true
26+
},
27+
"include": ["src"]
28+
}

examples/basic-demo/tsconfig.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"files": [],
3+
"references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }]
4+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"compilerOptions": {
3+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4+
"target": "ES2023",
5+
"lib": ["ES2023"],
6+
"module": "ESNext",
7+
"types": ["node"],
8+
"skipLibCheck": true,
9+
10+
/* Bundler mode */
11+
"moduleResolution": "bundler",
12+
"allowImportingTsExtensions": true,
13+
"verbatimModuleSyntax": true,
14+
"moduleDetection": "force",
15+
"noEmit": true,
16+
17+
/* Linting */
18+
"strict": true,
19+
"noUnusedLocals": true,
20+
"noUnusedParameters": true,
21+
"erasableSyntaxOnly": true,
22+
"noFallthroughCasesInSwitch": true,
23+
"noUncheckedSideEffectImports": true
24+
},
25+
"include": ["vite.config.ts"]
26+
}

0 commit comments

Comments
 (0)