# Koji Editor

A React editor component for Japanese classical texts with syntax highlighting and line numbers.

## Features

- **Vertical and Horizontal Writing Modes**: Supports both `vertical-rl` and `horizontal-tb` writing modes
- **Syntax Highlighting**: Uses CSS Custom Highlight API for efficient highlighting of:
  - Furigana (reading aids)
  - Kaeriten (return marks)
  - Okurigana (inflectional kana)
  - Annotations
  - Block and inline tags
- **Line Numbers**: Optional line number display with support for:
  - Logical lines (based on `\n` delimiters)
  - Visual lines (horizontal mode only, based on word wrapping)
  - Dynamic sizing for wrapped lines
- **ContentEditable**: Native browser editing with enhanced paste handling

## Installation

```bash
npm install koji-editor
```

## Usage

```tsx
import { KojiEditor } from 'koji-editor';
import 'koji-editor/style.css';

function App() {
  const [text, setText] = useState('');

  return (
    <KojiEditor
      writingMode="vertical"
      srcInput={text}
      showLineNumbers={true}
      lineNumberMode="logical"
      onInput={(editor) => setText(editor.text)}
      style={{ width: '600px', height: '400px' }}
    />
  );
}
```

## Props

### Core Props

- `writingMode?: 'vertical' | 'horizontal'` - Text direction (default: `'vertical'`)
- `srcInput?: string` - Initial text content
- `disabled?: boolean` - Disable editing
- `style?: React.CSSProperties` - Container styles

### Line Numbers

- `showLineNumbers?: boolean` - Display line numbers (default: `false`)
- `lineNumberMode?: 'logical' | 'visual'` - Line numbering mode (default: `'logical'`)
  - `'logical'`: Number lines based on `\n` delimiters
  - `'visual'`: Number lines based on visual wrapping (horizontal mode only)

### Highlighting

- `errors?: KojiParseError[]` - Error highlights
- `highlights?: Array<{ start: number; end: number; className?: string }>` - Custom highlights

### Callbacks

- `onInput?: (editor: EditorObject) => void` - Called when text changes
- `onFocused?: (editor: EditorObject) => void` - Called when editor gains focus
- `onBlurred?: (editor: EditorObject) => void` - Called when editor loses focus
- `onSelectionChange?: (editor: EditorObject) => void` - Called when selection changes

### EditorObject

All callbacks receive an `EditorObject` with:

```typescript
{
  text: string;
  tokens: KojiToken[];
  selection: { start: number; end: number; direction?: 'forward' | 'backward' | 'none' };
  isFocused: boolean;
  isDisabled: boolean;
  writingMode: 'vertical' | 'horizontal';
  errors: KojiParseError[];
}
```

### Ref API

For imperative control, you can use a ref to access editor methods:

```tsx
import { useRef } from 'react';
import { KojiEditor, KojiEditorRef } from 'koji-editor';

function App() {
  const editorRef = useRef<KojiEditorRef>(null);

  const insertAtCursor = () => {
    editorRef.current?.insertText('挿入テキスト');
  };

  return (
    <>
      <button onClick={insertAtCursor}>Insert Text</button>
      <KojiEditor ref={editorRef} writingMode="vertical" />
    </>
  );
}
```

#### Available Ref Methods

- `getEditorObject(): EditorObject` - Get current editor state
- `setText(text: string): void` - Set editor text
- `setSelection(start: number, end: number): void` - Set selection range
- `focus(): void` - Focus the editor
- `blur(): void` - Blur the editor
- `getText(): string` - Get current text
- `getTokens(): KojiToken[]` - Get tokenized content
- `getSelection(): { start, end, direction }` - Get current selection
- `insertText(text: string): void` - Insert text at cursor position
- `replaceText(start: number, end: number, text: string): void` - Replace text range

**Note:** Using ref methods will trigger the `onInput` callback with the updated editor state.

## Browser Support

- Requires CSS Custom Highlight API support (Chrome/Edge 105+, Safari 17.2+)
- Visual line mode uses Range.getClientRects() (not supported in Firefox vertical mode)

## Development

```bash
# Install dependencies
npm install

# Run Storybook
npm run storybook

# Build package
npm run build
```

## License

MIT
