Skip to content

Commit 3d1e8df

Browse files
docs: Remove optional UI components phase and renumber subsequent phases.
1 parent a3c958c commit 3d1e8df

File tree

2 files changed

+2
-150
lines changed

2 files changed

+2
-150
lines changed

plans/phases.md

Lines changed: 1 addition & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -785,148 +785,7 @@ export function useSpeechInputWithCursor(
785785

786786
---
787787

788-
## Phase 4: Optional UI Components
789-
790-
**Goal:** Provide composable, unstyled (headless) UI components for common use cases.
791-
792-
### 4.1 SpeechButton Component
793-
794-
Following headless UI best practices (like Radix UI, Headless UI):
795-
796-
```tsx
797-
// src/components/SpeechButton.tsx
798-
799-
import { forwardRef, type ReactNode, type ButtonHTMLAttributes } from 'react';
800-
import { useSpeechInput, type UseSpeechInputOptions } from '../hooks/useSpeechInput';
801-
802-
export interface SpeechButtonRenderProps {
803-
isListening: boolean;
804-
isSupported: boolean;
805-
permissionState: 'prompt' | 'granted' | 'denied' | 'unsupported';
806-
transcript: string;
807-
error: { type: string; message: string } | null;
808-
}
809-
810-
export interface SpeechButtonProps
811-
extends ButtonHTMLAttributes<HTMLButtonElement>,
812-
UseSpeechInputOptions {
813-
asChild?: boolean; // Radix-style composition
814-
}
815-
816-
export const SpeechButton = forwardRef<HTMLButtonElement, SpeechButtonProps>(
817-
function SpeechButton(
818-
{ asChild, onClick, ...props },
819-
ref
820-
) {
821-
const { isListening, toggle } = useSpeechInput(props);
822-
const Comp = asChild ? Slot : 'button';
823-
824-
return (
825-
<Comp
826-
ref={ref}
827-
onClick={(e) => {
828-
onClick?.(e);
829-
toggle();
830-
}}
831-
aria-pressed={isListening}
832-
{...props}
833-
/>
834-
);
835-
}
836-
);
837-
```
838-
839-
### 4.2 SpeechInput Component
840-
841-
Controlled input with speech integration:
842-
843-
```tsx
844-
// src/components/SpeechInput.tsx
845-
846-
import {
847-
forwardRef,
848-
useState,
849-
useRef,
850-
useImperativeHandle,
851-
type InputHTMLAttributes,
852-
type ReactNode
853-
} from 'react';
854-
import { useSpeechInputWithCursor } from '../hooks/useSpeechInputWithCursor';
855-
import type { UseSpeechInputOptions } from '../types';
856-
857-
export interface SpeechInputRenderProps {
858-
isListening: boolean;
859-
isSupported: boolean;
860-
permissionState: 'prompt' | 'granted' | 'denied' | 'unsupported';
861-
error: { type: string; message: string } | null;
862-
toggle: () => Promise<void>;
863-
}
864-
865-
export interface SpeechInputProps
866-
extends Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange'>,
867-
UseSpeechInputOptions {
868-
/** Controlled value */
869-
value: string;
870-
/** Change handler */
871-
onChange: (value: string) => void;
872-
/** Render prop for mic button */
873-
renderButton?: (props: SpeechInputRenderProps) => ReactNode;
874-
/** Container className */
875-
containerClassName?: string;
876-
}
877-
878-
export const SpeechInput = forwardRef<HTMLInputElement, SpeechInputProps>(
879-
function SpeechInput(
880-
{
881-
value,
882-
onChange,
883-
renderButton,
884-
containerClassName,
885-
...props
886-
},
887-
ref
888-
) {
889-
const inputRef = useRef<HTMLInputElement>(null);
890-
891-
useImperativeHandle(ref, () => inputRef.current!, []);
892-
893-
const speech = useSpeechInputWithCursor({
894-
inputRef,
895-
value,
896-
onChange,
897-
...props,
898-
});
899-
900-
return (
901-
<div className={containerClassName}>
902-
<input
903-
ref={inputRef}
904-
value={value}
905-
onChange={(e) => onChange(e.target.value)}
906-
{...props}
907-
/>
908-
{renderButton?.({
909-
isListening: speech.isListening,
910-
isSupported: speech.isSupported,
911-
permissionState: speech.permissionState,
912-
error: speech.error,
913-
toggle: speech.toggle,
914-
})}
915-
</div>
916-
);
917-
}
918-
);
919-
```
920-
921-
### Deliverables
922-
- [ ] `src/components/SpeechButton.tsx` — Headless speech toggle button
923-
- [ ] `src/components/SpeechInput.tsx` — Input with speech integration
924-
- [ ] Storybook stories for components
925-
- [ ] Accessibility tests (a11y)
926-
927-
---
928-
929-
## Phase 5: Documentation & Examples
788+
## Phase 4: Documentation & Examples
930789

931790
**Goal:** Create comprehensive documentation and example applications.
932791

plans/plan.md

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ react-web-speech/
3333
│ ├── index.ts # Main exports
3434
│ ├── hooks/
3535
│ │ └── useSpeechInput.ts # Primary hook
36-
│ ├── components/
37-
│ │ └── SpeechButton.tsx # Optional composable UI
3836
│ ├── core/
3937
│ │ ├── recognition.ts # Web Speech API wrapper
4038
│ │ ├── permissions.ts # Mic permission handling
@@ -308,12 +306,7 @@ export default defineConfig({
308306
3. Error handling with typed errors
309307
4. Configurable options (lang, continuous, etc.)
310308

311-
### Phase 4: Optional Components (Week 3)
312-
1. `SpeechButton` composable component
313-
2. Example/demo app
314-
3. Storybook documentation
315-
316-
### Phase 5: Polish & Release (Week 4)
309+
### Phase 4: Polish & Release (Week 3-4)
317310
1. Comprehensive tests
318311
2. Documentation and README
319312
3. npm publish and GitHub release

0 commit comments

Comments
 (0)