olu
RTL-first Flutter UI kit with zero dependencies.
Production-ready widgets for Arabic and multilingual apps: advanced typography (OLUText), responsive Bento dashboards (OLUBento), and RTL-aware carousels (OLUCarousel). Built with CustomPainter, implicit animations, and full ThemeData integration — no third-party packages.
Why olu?
| Problem | olu solution |
|---|---|
| Arabic justify / kashida breaks words or sacred phrases | Smart kashida engine with exclusions, font-aware tatweel, Mushaf variant |
| Mixed Arabic/Latin/CJK baseline misalignment | Script-aware spans, bidi isolation, auto-detection |
| RTL layouts feel bolted-on | Native RTL mirroring (Bento), swipe physics & indicators (Carousel) |
| Heavy carousel / grid dependencies | Zero deps — theme-only colors, lightweight painters |
Features
OLUText
Drop-in Text / RichText replacement with:
- Kashida & smart justify — sacred-word and hamza exclusions, font-aware tatweel scaling
- Global scripts — Arabic, Persian, Urdu, Hebrew, Latin, CJK with script-aware line height
- Bidi utilities —
OLUBidi.isolateLtr,normalizeMixed, mixed inline icons withoutWidgetSpan - Tajweed — grouped color spans (phase A) and per-glyph painter (phase B)
- Effects — gradient, shadow, stroke; marquee scrolling
- Links & rich spans —
OLULinkSpan,OLUArabicSpan,OLULatinSpan,OLUCjkSpan
OLUBento
Smart Bento grid with:
- RTL auto-mirroring, scroll, responsive breakpoints, drag reorder
- 16 preset tiles — Hero, Stat, Media, Banner, List, CTA, Icon, Chart, Profile, Progress, ProgressRing, Quote, Event, Alert, Rating, Toggle
OLUBentoThemeData— radius, padding, gaps, skeleton colors- Tile states — ready, loading, error, empty
OLUCarousel
RTL-aware carousel with:
- Autoplay, loop, external controller — pause on touch / manual navigation
- 3 indicator styles — glass dots (tappable), bar progress, numeric fraction
- Page transforms — scale and parallax peek effect
- RTL arrows & physics — direction-correct swipe and navigation
- 6 preset slides — Hero, Image, Product, Text, Stat, CTA
Installation
dependencies:
olu: ^1.0.0
flutter pub get
Import everything from a single entry point:
import 'package:olu/olu.dart';
Quick start
Theme setup (recommended)
Register theme extensions once in your MaterialApp:
MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
extensions: const [
OLUBentoThemeData(),
OLUCarouselThemeData(),
],
),
// ...
);
All widgets read colors from Theme.of(context) — no hard-coded palette.
OLUText
// Smart justify (kashida / word-spacing / Flutter justify by script)
OLUText(
'النص العربي',
textAlign: OLUTextAlign.justify,
style: Theme.of(context).textTheme.bodyLarge,
);
// Auto-detect mixed scripts
OLUText.auto('Price: \$99 / السعر ٩٩ ريال');
// Kashida with sacred-word exclusions (default)
OLUText(
'إن اللّٰه على كل شيء قدير',
textAlign: OLUTextAlign.kashidaJustify,
);
// Per-glyph tajweed (custom painter)
OLUText.tajweed(
'بِسْمِ اللَّهِ',
style: Theme.of(context).textTheme.headlineSmall,
tajweedRules: [
OLUTajweedRule(start: 0, end: 1, color: Theme.of(context).colorScheme.primary),
],
);
// RTL-safe inline icons (no WidgetSpan)
OLUText.mixed(
spans: [
OLUIconSpan(Icons.check, color: Theme.of(context).colorScheme.primary),
OLUArabicSpan(' عنصر القائمة'),
],
);
OLUBento
OLUBento(
crossAxisCount: 4,
gap: 12,
breakpoints: {480: 3, 720: 4, 1024: 6},
children: [
...OLUBentoLayouts.dashboard4Col(context),
OLUBentoItem(
colSpan: 2,
rowSpan: 1,
child: OLUBentoHeroTile(title: 'Welcome', subtitle: 'Dashboard'),
),
],
);
// All 16 tile types in one layout
OLUBento(
crossAxisCount: 2,
children: OLUBentoLayouts.fullCatalog(context),
);
Preset tiles: OLUBentoHeroTile, OLUBentoStatTile, OLUBentoMediaTile, OLUBentoBannerTile, OLUBentoListTile, OLUBentoCtaTile, OLUBentoIconTile, OLUBentoChartTile, OLUBentoProfileTile, OLUBentoProgressTile, OLUBentoProgressRingTile, OLUBentoQuoteTile, OLUBentoEventTile, OLUBentoAlertTile, OLUBentoRatingTile, OLUBentoToggleTile.
See doc/olu_bento_guide.md for layout presets, responsive breakpoints, and tile catalog.
OLUCarousel
// Autoplay hero banner with bar indicator
OLUCarousel(
height: 240,
autoPlay: true,
loop: true,
showArrows: true,
indicatorStyle: OLUCarouselIndicatorStyle.bar,
children: OLUCarouselLayouts.hero3(context),
);
// Peek carousel with scale transform + numeric indicator
OLUCarousel(
height: 200,
viewportFraction: 0.85,
enlargeStrategy: OLUCarouselEnlargeStrategy.scale,
indicatorStyle: OLUCarouselIndicatorStyle.number,
items: OLUCarouselLayouts.productStrip(context),
);
// External controller
final controller = OLUCarouselController();
OLUCarousel(controller: controller, height: 200, children: slides);
await controller.next();
Preset slides: OLUCarouselHeroSlide, OLUCarouselImageSlide, OLUCarouselProductSlide, OLUCarouselTextSlide, OLUCarouselStatSlide, OLUCarouselCtaSlide.
See doc/olu_carousel_guide.md for controller API, autoplay options, and indicator styles.
Documentation
| Guide | Contents |
|---|---|
| doc/olu_bento_guide.md | Tile catalog, OLUBentoLayouts, responsive grid, theme |
| doc/olu_carousel_guide.md | Autoplay, loop, indicators, transforms, preset slides |
| doc/olu_text_field_scope.md | Planned OLUTextField scope (v1.1) |
| CHANGELOG.md | Release history |
| API docs | Generated dartdoc on pub.flutter-io.cn |
Example app
A full showcase ships in the example/ directory:
cd example
flutter run
Demos include RTL/LTR toggle, dark/light mode, kashida exclusions, tajweed, mixed scripts, all 16 Bento tiles, and 6 Carousel slide types.
Platform support
| Platform | Supported |
|---|---|
| Android | ✓ |
| iOS | ✓ |
| Web | ✓ (use CanvasKit for Arabic — see below) |
| macOS | ✓ |
| Windows | ✓ |
| Linux | ✓ |
Recommended fonts
| Use case | Suggested fonts |
|---|---|
| General UI | Noto Naskh Arabic, Amiri |
| Quranic / Mushaf | KFGQPC Uthmanic script, Amiri Quran, Scheherazade New |
| Persian | Noto Naskh Arabic or Vazirmatn |
| Urdu | Noto Nastaliq Urdu (display), Noto Naskh Arabic (UI) |
Register fonts in your app's pubspec.yaml and set fontFamily on TextStyle, or use OLUTextVariant.mushaf for Quranic defaults.
Web (Flutter)
Arabic and complex scripts on Flutter web render most reliably with CanvasKit:
flutter run -d chrome --web-renderer canvaskit
flutter build web --web-renderer canvaskit
The HTML renderer may show joining or diacritic issues; prefer CanvasKit for production RTL apps.
Known limitations
Some RTL text issues are engine-level and cannot be fully fixed inside this package:
- Wrapped RTL selection rects — multi-line Arabic selection highlights may misalign (flutter#175983). Avoid
textAlign: OLUTextAlign.justifywithselectable: truewhen possible. - WidgetSpan in selectable text — baseline correction uses plain
TextSpanwhenselectable: true. - Per-glyph tajweed —
OLUText.tajweeduses a custom painter; not selectable in v1.0. - TextField RTL input — display (
OLUText) and input (TextField) are separate; see doc/olu_text_field_scope.md.
OLUText mitigates selection issues with selectionHeightStyle: BoxHeightStyle.includeLineSpacingMiddle (default) and forceTextDirection for single-language blocks.
Architecture
All widgets:
- Read colors and styles from
Theme.of(context) - Wrap roots in
RepaintBoundaryfor performance - Adapt automatically to
Directionality.of(context) - Support
keyandsemanticLabelfor accessibility
Zero external dependencies — only flutter SDK.
Testing
The package includes 80+ widget and unit tests:
flutter test
Contributing
Issues and pull requests are welcome on GitHub.
Before submitting, run:
dart format .
dart analyze
flutter test
License
MIT License. See LICENSE for details.
Libraries
- olu
- RTL-first Flutter UI package with zero dependencies.