yokogaki 0.10.2 copy "yokogaki: ^0.10.2" to clipboard
yokogaki: ^0.10.2 copied to clipboard

Flutter package for Japanese horizontal text (yokogaki) layout with ruby, kenten, warichu, and rich text support

yokogaki #

pub package License: MIT

Flutter package for Japanese horizontal text (yokogaki - 横書き) layout with advanced typography features including ruby, kenten, warichu, and rich text support.

Features #

  • Kinsoku Processing (禁則処理): Japanese line breaking rules

    • Line-start prohibition (行頭禁則, gyoto kinsoku)
    • Line-end prohibition (行末禁則, gyomatsu kinsoku)
    • Hanging characters (ぶら下げ, burasage)
    • Pushing-in characters (追い込み, oikomi)
  • Yakumono Adjustment (約物調整): Fine-tune punctuation positioning

    • Half-width yakumono handling
    • Gyoto indent for opening brackets
    • Consecutive yakumono spacing
  • Ruby Text (ルビ/振り仮名): Furigana support

    • Place ruby text above base characters
    • Multi-line ruby support (splits across line breaks)
    • Customizable ruby style
  • Kenten (圏点): Emphasis marks

    • Multiple styles: sesame, circles, triangles, squares, stars, diamonds, X marks
    • Place marks above characters for emphasis
    • Customizable kenten style
    • Combine with ruby text
  • Warichu (割注): Inline annotations

    • Two-line inline annotations
    • Automatically splits text into two rows
    • Displayed inline with main text
    • Combine with ruby and kenten
  • Text Decoration (上線/下線): Underline and overline support

    • Single line, double line, wavy line, dotted line
    • Works with ruby (automatic position adjustment)
  • Text Alignment (地付き): Line-level alignment

    • TextAlignment.start: Align to left (default)
    • TextAlignment.center: Center alignment
    • TextAlignment.end (地付き): Align to right
  • Text Indentation (字下げ): Character-based indentation

    • indent: Indent all lines (全行字下げ)
    • firstLineIndent: Indent first line only (段落字下げ)
  • Rich Text: Multiple styles in one text block

    • Span-based architecture for hierarchical text
    • Mix multiple colors, fonts, sizes, and weights
    • Per-span ruby, kenten, and warichu annotations
    • Powerful text composition with SimpleHorizontalTextSpan and GroupHorizontalTextSpan
  • Text Selection: Interactive text selection

    • Tap to select single character
    • Drag to select text range
    • Draggable selection handles
    • Context menu with copy/select all
    • Keyboard shortcuts (Ctrl+C, Ctrl+A)
    • Customizable selection color
    • Full support for all typography features

This package is part of the Japanese text layout suite:

Package Description
kinsoku Core text processing (line breaking, character classification)
tategaki Vertical text layout (縦書き)
yokogaki Horizontal text layout (this package)

Quick Start #

3ステップで横書きテキストを表示:

// 1. Import
import 'package:yokogaki/yokogaki.dart';

// 2. Widget内で使用
HorizontalText(
  text: 'こんにちは、世界!',
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 24),
  ),
)

ルビ付きの例:

HorizontalText(
  text: '日本語',
  rubyList: const [RubyText(startIndex: 0, length: 3, ruby: 'にほんご')],
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 32),
    rubyStyle: TextStyle(fontSize: 14),
  ),
)

Platform Support #

Platform Status Notes
Android ✅ Supported All features
iOS ✅ Supported All features
Web ✅ Supported All features
Windows ✅ Supported All features
macOS ✅ Supported All features
Linux ✅ Supported All features

Requirements:

  • Flutter: ≥1.17.0
  • Dart SDK: ≥3.10.3

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  yokogaki: ^0.10.1

Then run:

flutter pub get

Usage #

Basic Horizontal Text #

import 'package:flutter/material.dart';
import 'package:yokogaki/yokogaki.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return HorizontalText(
      text: 'これは横書きのテストです。',
      style: HorizontalTextStyle(
        baseStyle: TextStyle(fontSize: 24),
      ),
    );
  }
}

With Line Breaking #

HorizontalText(
  text: '吾輩は猫である。名前はまだ無い。どこで生まれたか頓と見当がつかぬ。',
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 24),
  ),
  maxWidth: 300,  // Enable line breaking at 300px
)

With Ruby Text (Furigana) #

HorizontalText(
  text: '日本語',
  rubyList: const [
    RubyText(startIndex: 0, length: 3, ruby: 'にほんご'),
  ],
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 32),
    rubyStyle: TextStyle(fontSize: 14, color: Colors.red),
  ),
)

With Kenten (Emphasis Marks) #

HorizontalText(
  text: '重要な部分を強調します。',
  kentenList: const [
    Kenten(startIndex: 0, length: 2, style: KentenStyle.sesame),
    Kenten(startIndex: 5, length: 2, style: KentenStyle.filledCircle),
  ],
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 28),
  ),
)

Available kenten styles:

  • KentenStyle.sesame - ゴマ点 (•)
  • KentenStyle.filledCircle - 黒丸 (●)
  • KentenStyle.circle - 白丸 (○)
  • KentenStyle.filledTriangle - 黒三角 (▲)
  • KentenStyle.triangle - 白三角 (△)
  • KentenStyle.doubleCircle - 二重丸 (◎)
  • KentenStyle.filledSquare - 黒四角 (■)
  • KentenStyle.square - 白四角 (□)
  • KentenStyle.filledDiamond - 黒菱形 (◆)
  • KentenStyle.diamond - 白菱形 (◇)
  • KentenStyle.filledStar - 黒星 (★)
  • KentenStyle.star - 白星 (☆)
  • KentenStyle.x - バツ (×)

With Text Decoration (Underline/Overline) #

HorizontalText(
  text: '下線と上線のテストです。',
  decorationList: const [
    TextDecorationAnnotation(
      startIndex: 0,
      endIndex: 2,
      type: TextDecorationLineType.underline,
    ),
    TextDecorationAnnotation(
      startIndex: 3,
      endIndex: 5,
      type: TextDecorationLineType.overline,
    ),
    TextDecorationAnnotation(
      startIndex: 6,
      endIndex: 8,
      type: TextDecorationLineType.wavyUnderline,
    ),
  ],
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 28),
  ),
)

With Text Alignment (地付き) #

HorizontalText(
  text: '右揃えの例です。',
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 24),
    alignment: TextAlignment.end, // 地付き - align to right
  ),
  maxWidth: 400,
)

With First Line Indent (段落字下げ) #

Traditional Japanese paragraph indentation where only the first line is indented:

HorizontalText(
  text: '吾輩は猫である。名前はまだ無い。どこで生まれたか頓と見当がつかぬ。',
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 20),
    firstLineIndent: 1, // First line indented by 1 character
  ),
  maxWidth: 300,
)

With Warichu (Inline Annotations) #

HorizontalText(
  text: '本文(注釈)の例です。',
  warichuList: const [
    Warichu(startIndex: 3, length: 0, warichu: 'ここに注釈'),
  ],
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 28),
  ),
)

Combined Ruby and Kenten #

HorizontalText(
  text: '重要な日本語を学びます。',
  rubyList: const [
    RubyText(startIndex: 0, length: 2, ruby: 'じゅうよう'),
    RubyText(startIndex: 3, length: 3, ruby: 'にほんご'),
  ],
  kentenList: const [
    Kenten(startIndex: 0, length: 2, style: KentenStyle.filledCircle),
  ],
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 26),
    rubyStyle: TextStyle(fontSize: 12, color: Colors.green),
  ),
)

Rich Text - Multiple Styles #

HorizontalRichText(
  span: GroupHorizontalTextSpan(
    children: [
      SimpleHorizontalTextSpan(
        text: 'これは',
        style: TextStyle(fontSize: 24, color: Colors.black),
      ),
      SimpleHorizontalTextSpan(
        text: '重要',
        style: TextStyle(fontSize: 24, color: Colors.red, fontWeight: FontWeight.bold),
        kentenList: const [
          Kenten(startIndex: 0, length: 2, style: KentenStyle.filledCircle),
        ],
      ),
      SimpleHorizontalTextSpan(
        text: 'な',
        style: TextStyle(fontSize: 24, color: Colors.black),
      ),
      SimpleHorizontalTextSpan(
        text: 'テキスト',
        style: TextStyle(fontSize: 24, color: Colors.blue, fontStyle: FontStyle.italic),
      ),
      SimpleHorizontalTextSpan(
        text: 'です。',
        style: TextStyle(fontSize: 24, color: Colors.black),
      ),
    ],
  ),
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 24),
  ),
)

Selectable Text #

SelectableHorizontalText(
  text: 'これは選択可能なテキストです。',
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 24),
  ),
  maxWidth: 350,
)

SelectionArea Integration (Selection API) #

Use SelectionAreaHorizontalText inside SelectionArea to enable unified text selection across multiple widgets:

SelectionArea(
  child: Column(
    children: [
      SelectableText('通常のテキスト'),
      SelectionAreaHorizontalText(
        text: '日本語の横書きテキスト',
        rubyList: [
          RubyText(startIndex: 0, length: 3, ruby: 'にほんご'),
        ],
        style: HorizontalTextStyle(
          baseStyle: TextStyle(fontSize: 24),
          rubyStyle: TextStyle(fontSize: 12),
        ),
      ),
    ],
  ),
)

This allows seamless text selection that spans across multiple selectable widgets.

Debug Grid #

HorizontalText(
  text: 'グリッド表示テスト',
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 32),
  ),
  showGrid: true,  // Show character grid for debugging
)

Example #

See the example directory for a complete demo app showcasing all features.

Use Cases / ユースケース #

ブログ・記事表示 #

一般的なWebコンテンツの表示:

HorizontalText(
  text: '今日は天気がよかったので、散歩に出かけました。'
      '公園では桜が満開で、とても綺麗でした。',
  style: HorizontalTextStyle(
    baseStyle: TextStyle(
      fontSize: 16,
      height: 1.8,
      fontFamily: 'NotoSansJP',
    ),
  ),
  maxWidth: 600,
)

教科書・教材 #

ルビと圏点を使った学習教材:

HorizontalText(
  text: '日本国憲法は国民主権を基本原理とする。',
  rubyList: const [
    RubyText(startIndex: 0, length: 4, ruby: 'にほんこくけんぽう'),
    RubyText(startIndex: 5, length: 4, ruby: 'こくみんしゅけん'),
    RubyText(startIndex: 10, length: 4, ruby: 'きほんげんり'),
  ],
  kentenList: const [
    Kenten(startIndex: 5, length: 4, style: KentenStyle.filledCircle),
  ],
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 20),
    rubyStyle: TextStyle(fontSize: 10, color: Colors.grey),
  ),
  maxWidth: 500,
)

新聞・ニュースアプリ #

注釈付きのニュース記事:

HorizontalText(
  text: '政府は新たな経済政策を発表した。',
  warichuList: const [
    Warichu(startIndex: 7, length: 0, warichu: '経済成長と物価安定を目指す'),
  ],
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 18),
  ),
  maxWidth: 400,
)

論文・学術文書 #

上線・下線による強調:

HorizontalText(
  text: '本研究の結論は以下の通りである。',
  decorationList: const [
    TextDecorationAnnotation(
      startIndex: 4,
      endIndex: 6,
      type: TextDecorationLineType.underline,
    ),
  ],
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 16),
  ),
)

チャット・メッセージアプリ #

選択可能なメッセージ表示:

SelectableHorizontalText(
  text: 'こんにちは!今日の予定はどうですか?',
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 16),
  ),
  maxWidth: 280,
)

リッチテキストエディタ #

複数スタイルの組み合わせ:

HorizontalRichText(
  span: GroupHorizontalTextSpan(
    children: [
      SimpleHorizontalTextSpan(
        text: '重要:',
        style: TextStyle(
          fontSize: 16,
          fontWeight: FontWeight.bold,
          color: Colors.red,
        ),
      ),
      SimpleHorizontalTextSpan(
        text: '明日は会議があります。',
        style: TextStyle(fontSize: 16),
      ),
    ],
  ),
  style: HorizontalTextStyle(
    baseStyle: TextStyle(fontSize: 16),
  ),
)

Performance #

yokogaki v0.6.0+ includes significant performance optimizations:

  • LRU Layout Cache: Automatic caching of layout calculations with 100-entry limit
  • TextPainter Reuse: Reduced memory allocations by reusing TextPainter instances
  • Smart Invalidation: Only recalculates when text, style, or width actually changes

Performance improvements:

  • ~70% faster layout calculation for repeated renders
  • ~50% fewer TextPainter allocations
  • Excellent performance for scrollable lists of Japanese text

Roadmap #

  • ✅ Basic horizontal text layout
  • ✅ Kinsoku processing
  • ✅ Yakumono adjustment
  • ✅ Line breaking with kinsoku rules
  • ✅ Ruby text (furigana) support
  • ✅ Kenten (emphasis marks)
  • ✅ Warichu (inline annotations)
  • ✅ Rich text with multiple styles
  • ✅ Performance optimizations
  • ✅ Text selection support
  • ✅ Text decoration (underline/overline)
  • ✅ Text alignment (地付き)
  • ✅ Selection API integration (SelectionArea support)

All planned features are now complete!

License #

MIT License - see LICENSE file for details

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

References #

1
likes
160
points
237
downloads

Publisher

verified publisherpub.nyapic.com

Weekly Downloads

Flutter package for Japanese horizontal text (yokogaki) layout with ruby, kenten, warichu, and rich text support

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, kinsoku

More

Packages that depend on yokogaki