From cb182461b21b14e24d2ac0aae39d056a7471e51b Mon Sep 17 00:00:00 2001 From: Anilcan Cakir Date: Tue, 31 Mar 2026 20:39:31 +0300 Subject: [PATCH 1/3] chore: add GitHub Copilot configuration converted from Claude Code Generate copilot-instructions.md, path-scoped .instructions.md files, release prompt, agent definitions, and sync script from existing CLAUDE.md, .claude/rules/, .claude/commands/, and skills/. --- .github/agents/wind-doc-writer.agent.md | 81 +++++++++++ .github/agents/wind-example-builder.agent.md | 98 ++++++++++++++ .github/agents/wind-ui.agent.md | 127 ++++++++++++++++++ .github/copilot-instructions.md | 71 ++++++++++ .github/instructions/docs.instructions.md | 28 ++++ .../example-pages.instructions.md | 22 +++ .github/instructions/parsers.instructions.md | 22 +++ .github/instructions/tests.instructions.md | 21 +++ .github/instructions/widgets.instructions.md | 22 +++ .github/prompts/release.prompt.md | 98 ++++++++++++++ .github/scripts/sync-cc-to-copilot.sh | 43 ++++++ 11 files changed, 633 insertions(+) create mode 100644 .github/agents/wind-doc-writer.agent.md create mode 100644 .github/agents/wind-example-builder.agent.md create mode 100644 .github/agents/wind-ui.agent.md create mode 100644 .github/copilot-instructions.md create mode 100644 .github/instructions/docs.instructions.md create mode 100644 .github/instructions/example-pages.instructions.md create mode 100644 .github/instructions/parsers.instructions.md create mode 100644 .github/instructions/tests.instructions.md create mode 100644 .github/instructions/widgets.instructions.md create mode 100644 .github/prompts/release.prompt.md create mode 100755 .github/scripts/sync-cc-to-copilot.sh diff --git a/.github/agents/wind-doc-writer.agent.md b/.github/agents/wind-doc-writer.agent.md new file mode 100644 index 0000000..750e3c8 --- /dev/null +++ b/.github/agents/wind-doc-writer.agent.md @@ -0,0 +1,81 @@ +--- +name: 'wind-doc-writer' +description: 'Write and update Wind framework documentation following TailwindCSS patterns and project conventions' +tools: ['read', 'edit', 'create_file', 'search'] +--- + +# Wind Documentation Writer + +Write documentation for Wind framework following TailwindCSS patterns and existing project conventions. + +## Source Code First + +**ALWAYS base documentation on actual source code in `lib/src/`.** + +Before writing ANY documentation: + +1. **Read the implementation** — Find and read the relevant source file: + - Widgets → `lib/src/widgets/` + - Parsers → `lib/src/parser/parsers/` + - Theme → `lib/src/theme/` + - Core → `lib/src/core/` + +2. **Extract from code** — Document what the code ACTUALLY does: + - Supported className values from parser regex/switch cases + - Widget props from constructor parameters + - Default values from code, not assumptions + +3. **Verify examples work** — Code snippets must match implementation behavior + +## Documentation Structure + +**Section Order (Utilities):** +1. H1 Title + Description +2. Table of Contents (MANDATORY) +3. x-preview + code block +4. Basic Usage +5. Quick Reference table +6. Variants +7. Responsive Design +8. Dark Mode +9. Arbitrary Values +10. Customizing Theme +11. Related Documentation + +**Section Order (Widgets):** +1. H1 Title + Description +2. Table of Contents (MANDATORY) +3. x-preview + code block +4. Basic Usage +5. Constructor +6. Props table +7. Layout Modes +8. Event Handling +9. State Variants +10. Styling Examples +11. All Supported Classes +12. Customizing Theme +13. Related Documentation + +## x-preview Components + +```html + +``` + +When adding NEW x-preview or MODIFYING code snippets, add a TODO comment: + +```html + + + +``` + +## Formatting Rules + +- One `#` title per file +- Code blocks use `dart` language tag +- Props table: left-aligned columns, backtick all code values +- Required props show `**Required**` in Default column +- Keep code examples short, realistic, and copy-pasteable +- Related docs at bottom with relative links diff --git a/.github/agents/wind-example-builder.agent.md b/.github/agents/wind-example-builder.agent.md new file mode 100644 index 0000000..aa689a2 --- /dev/null +++ b/.github/agents/wind-example-builder.agent.md @@ -0,0 +1,98 @@ +--- +name: 'wind-example-builder' +description: 'Build, update, and manage Wind framework example pages for documentation demos' +tools: ['read', 'edit', 'create_file', 'search', 'run_terminal_cmd'] +--- + +# Wind Example Builder + +Build example pages for Wind framework documentation. + +## Path Format Convention + +| Component | Format | Example | +|-----------|--------|---------| +| Folder name | **HYPHENS** | `core-concepts/`, `getting-started/` | +| File name | **UNDERSCORES** | `state_management_overview.dart` | +| Route key | `/{folder-hyphen}/{file_underscore}` | `/core-concepts/state_management_overview` | +| x-preview path | `{folder-hyphen}/{file_underscore}` | `core-concepts/state_management_overview` | +| source attr | `example/lib/pages/{folder-hyphen}/{file_underscore}.dart` | Full path | + +## Workflow + +1. **Scan TODOs:** Find `` comments in `doc/` +2. **Validate paths:** Folder = hyphens, file = underscores +3. **Create page** at `example/lib/pages/{category}/{page_name}.dart` +4. **Register route** in `example/lib/routes.dart` +5. **Remove TODO** from doc file (keep only x-preview tag) + +## Page Template + +```dart +import 'package:flutter/material.dart'; +import 'package:fluttersdk_wind/fluttersdk_wind.dart'; + +class {PageName}ExamplePage extends StatelessWidget { + const {PageName}ExamplePage({super.key}); + + @override + Widget build(BuildContext context) { + return WDiv( + className: 'w-full h-full overflow-y-auto p-4', + scrollPrimary: true, + child: WDiv( + className: 'flex flex-col gap-6 max-w-4xl mx-auto', + children: [ + _buildHeader(), + _buildSection( + title: 'Section Title', + description: 'What this demonstrates', + child: /* Demo widget */, + ), + ], + ), + ); + } + + Widget _buildHeader() { + return WDiv( + className: 'bg-gradient-to-r from-blue-500 to-purple-600 rounded-xl p-6', + child: WText('Page Title', className: 'text-2xl font-bold text-white'), + ); + } + + Widget _buildSection({ + required String title, + required String description, + required Widget child, + }) { + return WDiv( + className: 'flex flex-col gap-4 p-4 bg-white dark:bg-slate-800 rounded-lg shadow-sm', + children: [ + WText(title, className: 'text-lg font-semibold text-slate-900 dark:text-white'), + WText(description, className: 'text-sm text-slate-600 dark:text-slate-400'), + child, + ], + ); + } +} +``` + +## State Prefix Rules + +| Widget | State Support | Notes | +|--------|--------------|-------| +| `WButton` | Built-in | Has internal state management | +| `WInput` | Built-in | Has focus/hover detection | +| `WAnchor` | Provider | Provides state to descendants | +| `WDiv` | Conditional | Auto-wraps ONLY if className contains `hover:`/`focus:`/`active:` | + +## Quality Checklist + +- Page renders without errors +- Demonstrates documented feature accurately +- Uses Wind utilities correctly (className, not inline styles) +- Route registered and accessible +- TODO removed from doc file +- Always include dark mode variants +- Use realistic content, not "Lorem ipsum" diff --git a/.github/agents/wind-ui.agent.md b/.github/agents/wind-ui.agent.md new file mode 100644 index 0000000..96167db --- /dev/null +++ b/.github/agents/wind-ui.agent.md @@ -0,0 +1,127 @@ +--- +name: 'wind-ui' +description: 'Wind framework expert — className patterns, layout rules, widget composition, responsive/dark mode styling' +tools: ['read', 'edit', 'create_file', 'search', 'run_terminal_cmd'] +--- + +# Wind Framework + +Utility-first Flutter UI. Styling via `className` strings → `WindParser` → `WindStyle` → Widget tree. + +## Widgets + +| Widget | Purpose | Key Props | +|--------|---------|-----------| +| `WDiv` | Container/layout | `className`, `child`/`children`, `states`, `scrollPrimary` | +| `WText` | Text | `data`, `className`, `selectable` | +| `WButton` | Button | `child`, `onTap`, `isLoading`, `disabled` | +| `WInput` | Text input | `value`, `onChanged`, `type`, `placeholder` | +| `WSelect` | Dropdown | `options`, `value`, `onChange`, `isMulti`, `searchable`, `onSearch`, `menuClassName` | +| `WCheckbox` | Checkbox | `value`, `onChanged`, `iconClassName` | +| `WImage` | Image | `src` (url/`asset://`), `alt`, `placeholder`, `errorBuilder` | +| `WSvg` | SVG | `src` or `WSvg.string(svgString:)` | +| `WIcon` | Icon | `icon` (IconData), `semanticLabel` | +| `WPopover` | Overlay | `triggerBuilder`, `contentBuilder`, `alignment`, `controller`, `offset`, `maxHeight` | +| `WSpacer` | Spacing | `className` — lightweight SizedBox (`h-*`/`w-*`) | +| `WFormInput` | Validated input | `validator`, `label`, `hint`, `labelClassName`, `errorClassName` | +| `WFormSelect` | Validated select | Same as WSelect + `validator`, `label` | +| `WFormMultiSelect` | Multi-select | `values`, `onMultiChange`, `onCreateOption` | +| `WFormCheckbox` | Validated checkbox | Same as WCheckbox + `validator` | +| `WFormDatePicker` | Date picker | `value`, `onChange`, `validator`, `minDate`, `maxDate` | +| `WAnchor` | State wrapper | `onTap`, `onLongPress`, `isDisabled`, `states` | + +All widgets accept `className` and `states` (Set\). + +## States & Prefixes + +**Interaction:** `hover:`, `focus:`, `disabled:`, `loading:`, `checked:`, `error:`, `open:`, `selected:` + +**Dark mode:** `dark:bg-gray-900 dark:text-white` + +**Responsive (mobile-first):** `sm:` (640), `md:` (768), `lg:` (1024), `xl:` (1280), `2xl:` (1536) + +**Platform:** `mobile:`, `macos:`, `windows:`, `web:`, `ios:`, `android:` + +WDiv auto-wraps in WAnchor when `hover:`/`focus:`/`active:` prefixes are detected. + +## Common Patterns + +### Layout +```dart +WDiv(className: 'flex flex-col md:flex-row gap-4 p-6') +WDiv(className: 'grid grid-cols-2 md:grid-cols-3 gap-4') +WDiv(className: 'wrap gap-2', children: [...]) // Wrapping layout +WDiv(className: 'flex justify-center items-center h-full') +``` + +### Scrollable Content +```dart +WDiv( + className: 'overflow-y-auto max-h-[300px] p-4', + child: content, +) +WDiv( + className: 'overflow-y-auto flex flex-col gap-6 p-4 lg:p-6', + scrollPrimary: true, + children: [/* page content */], +) +``` + +### Card +```dart +WDiv( + className: 'bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6 border border-gray-100 dark:border-gray-700', + children: [ + WText('Title', className: 'text-xl font-bold text-gray-900 dark:text-white'), + WText('Body', className: 'text-sm text-gray-600 dark:text-gray-400 mt-2'), + ], +) +``` + +### Button +```dart +WButton( + className: 'bg-primary hover:bg-green-600 text-white px-4 py-2 rounded-lg disabled:opacity-50', + onTap: () {}, + isLoading: isSubmitting, + child: WText('Submit'), +) +``` + +### Form Input +```dart +WFormInput( + className: 'w-full px-3 py-3 rounded-lg bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 focus:border-primary focus:ring-2 focus:ring-primary/20 error:border-red-500', + label: 'Email', + labelClassName: 'text-sm font-medium text-gray-700 dark:text-gray-300', + errorClassName: 'text-xs text-red-500 mt-1', + validator: (v) => v?.contains('@') == true ? null : 'Invalid email', +) +``` + +### Theme Setup +```dart +WindTheme( + initialData: WindThemeData( + colors: {...WindThemeData.defaultColors, 'primary': {'500': Color(0xFF009E60)}}, + ), + child: MaterialApp(...), +) +``` + +## Key Rules + +1. **Last class wins** — later classes override earlier ones for same property +2. **Spacing scale** — N * 4px: `p-4` = 16px, `gap-2` = 8px +3. **Arbitrary values** — bracket syntax: `w-[200px]`, `text-[#FF0000]` +4. **Opacity shorthand** — `bg-red-500/50`, `text-blue-500/75` +5. **Cache** — WindParser caches results; call `WindParser.clearCache()` in tests + +## Gotchas + +| Issue | Solution | +|-------|----------| +| className typos silently fail | No compile errors — double-check spelling | +| `overflow-y-auto` without height | Add `max-h-*` or parent flex constraint | +| Dark mode missing | Every bg/text/border needs `dark:` variant | +| **`flex-wrap` is a NO-OP** | Use `wrap gap-2` instead. `flex` creates Row/Column which cannot wrap | diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..d54b521 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,71 @@ +# Wind UI — Tailwind-Inspired Flutter Styling Framework + +Utility-first Flutter UI plugin. Translates `className` strings (Tailwind syntax) into Flutter widget trees via modular parsing architecture. + +**Version:** 1.0.0-alpha.4 · **Branch:** `v1` (master = v0, do NOT touch) · **Dart:** >=3.4.0 · **Flutter:** >=3.27.0 + +## Architecture + +``` +lib/src/ +├── widgets/ # 20 W-prefix widgets (WDiv, WText, WButton, WSvg, WDynamic...) +├── parser/ +│ ├── wind_parser.dart # Orchestrator — routes tokens to 17 parsers +│ ├── wind_style.dart # Immutable style value object (parse output) +│ ├── wind_context.dart # Theme + breakpoint + brightness + platform + states +│ └── parsers/ # 17 domain parsers (bg, border, flex, text, shadow...) +├── theme/ +│ ├── wind_theme.dart # WindTheme widget + WindThemeController +│ ├── wind_theme_data.dart # Config: colors, screens, spacing, fonts +│ └── defaults/ # 16 default token scales +├── dynamic/ # WDynamic — JSON → widget tree (server-driven UI) +├── state/ # WindAnchorStateProvider (hover/focus/press via InheritedWidget) +└── utils/ # Extensions, helpers, color utils, logger +``` + +**Data flow:** `className` → WindParser.parse() → 17 parsers (first-match-wins) → WindStyle → Widget.build() + +**Cache key:** className + breakpoint + brightness + platform + sorted states + +## Key Conventions + +- All widgets use `W` prefix: `WDiv`, `WButton`, `WText`, `WFormInput`, `WSvg` +- `className` is the primary styling API — takes precedence over explicit style properties +- `child` XOR `children` — never both +- Last class wins — later classes override earlier ones for same property +- Spacing scale: N * 4px (`p-4` = 16px, `gap-2` = 8px) +- Arbitrary values: bracket syntax `w-[200px]`, `text-[#FF0000]` +- TDD — failing test first, red-green-refactor +- Zero tolerance — linter zero warnings, no suppressions + +## Key Gotchas + +| Mistake | Fix | +|---------|-----| +| `className: 'flex-wrap'` | Use `wrap gap-2` — flex-wrap is a no-op | +| `WDiv(child: x, children: [...])` | `child` XOR `children`, never both | +| `overflow-y-auto` without `scrollPrimary: true` | Add it for iOS tap-to-top | +| `w-full` inside Row/flex-row | Use `flex-1` — w-full causes overflow | +| No `dark:` variant on colors | **Always** pair: `bg-white dark:bg-gray-800` | +| `WIcon(Icons.settings)` | Use `Icons.settings_outlined` — outlined only | +| className typo | Fails silently — parser ignores unknown tokens | +| `h-full` inside scrollable parent | Use `min-h-screen` — h-full = infinite height error | +| Forgetting `WindParser.clearCache()` in tests | Cache persists between tests | + +## Post-Change Checklist + +After ANY source code change, sync before committing: + +1. **`doc/`** — Update relevant documentation files +2. **`skills/wind-ui/`** — Update SKILL.md and references if API/widget changes +3. **`example/lib/pages/`** — Update or create demo pages +4. **`CHANGELOG.md`** — Add entry under `[Unreleased]` +5. **`README.md`** — Update if new widgets, features, or API changes + +## Parser Development + +1. Find parser in `lib/src/parser/parsers/` (or create new one implementing `WindParserInterface`) +2. Add property to `WindStyle` if needed (immutable — use `copyWith`) +3. Write failing test first in `test/parser/parsers/{name}_parser_test.dart` +4. Implement in parser +5. Run post-change checklist diff --git a/.github/instructions/docs.instructions.md b/.github/instructions/docs.instructions.md new file mode 100644 index 0000000..5ae8705 --- /dev/null +++ b/.github/instructions/docs.instructions.md @@ -0,0 +1,28 @@ +--- +name: 'Documentation Conventions' +description: 'Formatting rules for Wind framework documentation files in doc/' +applyTo: 'doc/**/*.md' +--- + +# Documentation Domain + +- One `#` title per file — widget name or concept name. One-line description immediately after +- Table of Contents with `[Section Name](#section-name)` links after description +- `` for live demos +- Section anchors: `` before each `##` heading +- Code blocks always use `dart` language specifier +- Props table format — left-aligned columns, backtick all code: + ``` + | Prop | Type | Default | Description | + |:-----|:-----|:--------|:------------| + | `className` | `String?` | `null` | Wind utility classes. | + ``` +- Required props show `**Required**` in Default column +- Constructor section shows full signature with defaults +- Heading hierarchy: `#` page title → `##` main sections → `###` subsections. Never skip levels +- x-preview `path` matches `example/lib/pages/{path}.dart` without extension +- x-preview `size`: `sm` (compact), `md` (standard), `lg` (full-width) +- Keep code examples short, realistic, and copy-pasteable +- Related docs at bottom: `- [Widget Name](../widgets/widget-name.md)` +- Do NOT restructure sections that haven't changed — preserve existing format exactly +- When adding new sections, match the style of adjacent sections in the same file diff --git a/.github/instructions/example-pages.instructions.md b/.github/instructions/example-pages.instructions.md new file mode 100644 index 0000000..37caff1 --- /dev/null +++ b/.github/instructions/example-pages.instructions.md @@ -0,0 +1,22 @@ +--- +name: 'Example Page Conventions' +description: 'Structure and patterns for Wind framework demo pages in example/lib/pages/' +applyTo: 'example/lib/pages/**/*.dart' +--- + +# Example Pages Domain + +- File name: `{feature_name}.dart` (snake_case). Class: `{FeatureName}ExamplePage` +- Extend `StatefulWidget` for interactive demos (state toggles, counters, loading simulation) +- Root widget: `WDiv(className: 'w-full h-full overflow-y-auto p-4', child: ...)` — always scrollable +- Content wrapper: `WDiv(className: 'flex flex-col gap-6', children: [_buildHeader(), ...sections])` +- Header: gradient WDiv with title (text-lg font-bold text-white) + description (text-sm) +- Use `_buildSection({title, description, children})` helper for consistent section layout +- Section title: `text-lg font-semibold text-gray-900 dark:text-white` +- Section description: `text-sm text-gray-600 dark:text-gray-400 mb-4` +- Always include dark mode variants in all className strings +- Show multiple variants of the component: basic, styled, states (hover, disabled, loading), responsive +- Include interactive state demos: `setState(() => _isLoading = !_isLoading)` +- Use realistic content — names, emails, descriptions — not "Lorem ipsum" +- Each page demonstrates ONE widget or concept thoroughly, not multiple +- These pages are referenced by `doc/` via `` — keep file paths stable diff --git a/.github/instructions/parsers.instructions.md b/.github/instructions/parsers.instructions.md new file mode 100644 index 0000000..e47ce26 --- /dev/null +++ b/.github/instructions/parsers.instructions.md @@ -0,0 +1,22 @@ +--- +name: 'Parser Conventions' +description: 'Implementation patterns for Wind className parsers' +applyTo: 'lib/src/parser/**/*.dart' +--- + +# Parser Domain + +- Every parser implements `WindParserInterface` with exactly two methods: `canParse()` and `parse()` +- `canParse()` must be O(1) — use `startsWith()` or pre-compiled `static final RegExp`. No heavy logic +- `parse()` iterates classes in **reverse** (last class wins semantics). Forward iteration is a bug +- Return `styles.copyWith(...)` from parse() — never return null, never mutate input +- If `classes == null`, return `styles` unchanged immediately +- Use named RegExp capture groups: `(?p|pt|pr|pb|pl|px|py)` — not positional groups +- Prefix stripping (`hover:`, `dark:`, `md:`) happens in WindParser before delegation — parsers never see prefixes +- First-match-wins routing: WindParser checks `canParse()` across all parsers — first `true` wins. Order matters +- One parser per file in `parsers/`. File name matches domain: `padding_parser.dart`, `border_parser.dart` +- Register new parsers in `WindParser._parserMap` — key is descriptive string, value is const instance +- `WindStyle` is immutable — properties are nullable. Merge with existing: `pTop ?? styles.padding?.top ?? 0` +- Theme value resolution via `context.theme.getSpacing()`, `context.theme.getColor()` — never hardcode values +- Arbitrary values use `[...]` bracket syntax: `p-[10px]`, `bg-[#FF5733]`. Parse brackets before theme lookup +- Cache key = className + breakpoint + brightness + platform + sorted states. Call `WindParser.clearCache()` in tests diff --git a/.github/instructions/tests.instructions.md b/.github/instructions/tests.instructions.md new file mode 100644 index 0000000..b65d689 --- /dev/null +++ b/.github/instructions/tests.instructions.md @@ -0,0 +1,21 @@ +--- +name: 'Testing Conventions' +description: 'Test structure, helpers, and patterns for Wind framework tests' +applyTo: 'test/**/*.dart' +--- + +# Testing Domain + +- Test structure mirrors `lib/src/` exactly: `test/parser/parsers/`, `test/widgets/`, `test/theme/`, `test/dynamic/` +- Every Wind widget test needs `wrapWithTheme()` helper — wraps in `MaterialApp > WindTheme > Scaffold` +- Parser tests use `createTestContext()` helper with named params: `brightness`, `activeBreakpoint`, `isHovering`, etc. +- Always `WindParser.clearCache()` in `setUp()` — cache persists between tests and causes false positives +- Use `group()` for logical grouping by feature, `testWidgets()` for widget tests, `test()` for pure logic +- Always `await tester.pumpWidget()`, `await tester.tap()`, `await tester.pump()` — missing await = flaky test +- Use `pumpAndSettle()` only for animations, `pump()` for single-frame rebuilds +- Parser tests: initialize parser + context in `setUp()` with `late` keyword +- Widget tests: test behavior (taps, state changes), not implementation details +- Expect patterns: `findsOneWidget`, `findsNothing`, `findsWidgets`, `isTrue`, `isA()` +- Test both theme-scale values (`p-4`) and arbitrary values (`p-[10px]`) for parser coverage +- Test dark mode: pass `brightness: Brightness.dark` to `createTestContext()` +- Test edge cases: null classes, empty string, conflicting classes (last wins), unknown tokens (ignored) diff --git a/.github/instructions/widgets.instructions.md b/.github/instructions/widgets.instructions.md new file mode 100644 index 0000000..c7fae72 --- /dev/null +++ b/.github/instructions/widgets.instructions.md @@ -0,0 +1,22 @@ +--- +name: 'Widget Conventions' +description: 'W-prefix widget hierarchy, constructor patterns, and state handling' +applyTo: 'lib/src/widgets/**/*.dart' +--- + +# Widget Domain + +- All widgets use `W` prefix: `WDiv`, `WButton`, `WText`, `WFormInput`, `WSvg` +- Form-integrated variants: `WForm{Feature}` (WFormInput, WFormSelect, WFormCheckbox, WFormDatePicker) +- Always `const` constructor with `super.key` first, required params next, optional last, trailing commas +- One class per file named after the widget: `w_button.dart` → `WButton` + `_WButtonState` +- `className` is the primary styling API — it takes precedence over any explicit style properties +- Widget build flow: parse className → detect displayType (flex/grid/block) → build minimal widget tree +- Use `WindParser.parse(className, WindContext.of(context), states: states)` — always with context +- WAnchor is required for `hover:`, `focus:`, `active:` states — WDiv auto-wraps if these prefixes detected +- `child` XOR `children` — never both. `child` for single content, `children` for flex/grid layouts +- Loading state (`isLoading: true`) disables all callbacks and activates `loading:` prefixed classes +- Disabled state (`disabled: true`) activates `disabled:` prefixed classes +- Custom states via `Set? states` parameter — used with matching prefixes like `selected:`, `active:` +- Never hardcode colors or sizes — resolve through className or theme +- DartDoc: `/// **The Utility-First [Name]**` header, then `### Supported Features:` and `### Example Usage:` sections diff --git a/.github/prompts/release.prompt.md b/.github/prompts/release.prompt.md new file mode 100644 index 0000000..884d4b9 --- /dev/null +++ b/.github/prompts/release.prompt.md @@ -0,0 +1,98 @@ +--- +name: 'release' +description: 'Prepare a new release — version bump, changelog, GitHub Release which triggers validate + publish to pub.dev' +agent: 'agent' +argument-hint: 'Target version (e.g. 1.0.0-alpha.5, 1.0.0-beta.1, 1.0.0)' +tools: ['read', 'edit', 'run_terminal_cmd', 'search'] +--- + +## Context + +Run these commands and use the output: + +- `grep 'version:' pubspec.yaml` — current version +- `git branch --show-current` — current branch +- `git tag -l | sort -V | tail -10` — recent git tags +- `gh release list --limit 5` — recent GitHub releases +- `sed -n '/## \[Unreleased\]/,/^## \[/p' CHANGELOG.md | head -40` — unreleased changes +- `git log $(git describe --tags --abbrev=0 2>/dev/null || echo HEAD~20)..HEAD --oneline` — commits since last tag +- `flutter test 2>&1 | tail -3` — test status +- `dart analyze 2>&1 | tail -3` — analyzer status + +## Arguments + +${input:version:Target version to release (e.g. 1.0.0-alpha.5). Leave empty to auto-increment.} + +## Your Task + +Prepare a new release for the **Wind UI** Flutter package. Follow this checklist precisely: + +### Phase 1: Validation + +1. **Branch check** — Must be on `v1` branch. If not, STOP and warn. +2. **Clean tree** — `git status` must show no uncommitted changes. If dirty, STOP and warn. +3. **Tests** — All tests must pass. If failing, STOP and report. +4. **Analyzer** — Zero issues required. If issues, STOP and report. +5. **Version** — Determine the new version from the provided argument or auto-increment. + +### Phase 2: Version Bump + +Update the version string in ALL of these files: + +| File | What to update | +|------|----------------| +| `pubspec.yaml` | `version:` field | +| `CHANGELOG.md` | Move `[Unreleased]` content to `[{version}] - {YYYY-MM-DD}`, add empty `[Unreleased]` above | +| `CLAUDE.md` | `**Version:**` line | +| `doc/getting-started/installation.md` | `fluttersdk_wind: ^{version}` in the yaml code block | + +### Phase 3: Changelog Enhancement + +Review the `[Unreleased]` section and the git log since the last tag: + +1. **Cross-reference** — Ensure every significant commit is reflected in CHANGELOG.md +2. **Missing entries** — Add any commits that introduced features, fixes, or improvements but were not logged +3. **Categorize** using: `### New Features`, `### Bug Fixes`, `### Improvements`, `### Breaking Changes` +4. **Entry format** — `- **Short Title**: One-line description` +5. **Date** — Use today's date in `YYYY-MM-DD` format + +### Phase 4: README Sync + +Check README.md for version-specific content that needs updating (badges, install examples, outdated code). + +### Phase 5: Local Verification + +Run all checks locally — ALL must pass: + +1. `dart format --set-exit-if-changed .` — must be clean +2. `dart analyze` — must be zero issues +3. `flutter test` — must all pass +4. `dart pub publish --dry-run` — must be zero warnings +5. Review all changed files with `git diff` + +If dry-run fails, STOP and fix before proceeding. + +### Phase 6: Commit & Push + +1. Stage all modified files +2. Create a single commit: `chore(release): {version}` +3. Push to remote: `git push` + +### Phase 7: Create GitHub Release + +Create a GitHub Release using `gh` CLI: + +```bash +gh release create {version} \ + --target v1 \ + --title "v{version}" \ + [--prerelease] \ + --notes "{changelog content}" +``` + +- Contains `alpha`, `beta`, or `rc` → add `--prerelease` flag +- After creating, watch the publish workflow: `gh run list --workflow=publish.yml --limit 1` + +### Output + +Present a summary with: GitHub Release URL, changed files, changelog counts, local verification results, pub.dev publish status. diff --git a/.github/scripts/sync-cc-to-copilot.sh b/.github/scripts/sync-cc-to-copilot.sh new file mode 100755 index 0000000..0a9b604 --- /dev/null +++ b/.github/scripts/sync-cc-to-copilot.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Sync Claude Code rules (.claude/rules/) → GitHub Copilot instructions (.github/instructions/) +# Run from project root: bash .github/scripts/sync-cc-to-copilot.sh + +set -euo pipefail + +RULES_DIR=".claude/rules" +INSTRUCTIONS_DIR=".github/instructions" + +mkdir -p "$INSTRUCTIONS_DIR" + +for rule in "$RULES_DIR"/*.md; do + [ -f "$rule" ] || continue + + name=$(basename "$rule" .md) + target="$INSTRUCTIONS_DIR/${name}.instructions.md" + + # Extract frontmatter fields + path_glob=$(sed -n '/^---$/,/^---$/{ /^path:/{ s/^path: *"*\(.*\)"*/\1/; p; } }' "$rule") + + # Extract body (everything after second ---) + body=$(sed '1,/^---$/{ /^---$/!d; }; /^---$/{ N; d; }' "$rule" | sed '1,/^---$/d') + # Simpler: skip first 3 lines (---, path:, ---) then take the rest + body=$(awk 'BEGIN{c=0} /^---$/{c++; next} c>=2{print}' "$rule") + + # Generate human-readable name from filename + display_name=$(echo "$name" | sed 's/-/ /g; s/\b\(.\)/\u\1/g') + + # Write Copilot instruction file + cat > "$target" < Date: Tue, 31 Mar 2026 20:41:47 +0300 Subject: [PATCH 2/3] chore: remove Copilot agents and prompts directories --- .github/agents/wind-doc-writer.agent.md | 81 ------------ .github/agents/wind-example-builder.agent.md | 98 -------------- .github/agents/wind-ui.agent.md | 127 ------------------- .github/prompts/release.prompt.md | 98 -------------- .github/scripts/sync-cc-to-copilot.sh | 4 +- 5 files changed, 1 insertion(+), 407 deletions(-) delete mode 100644 .github/agents/wind-doc-writer.agent.md delete mode 100644 .github/agents/wind-example-builder.agent.md delete mode 100644 .github/agents/wind-ui.agent.md delete mode 100644 .github/prompts/release.prompt.md diff --git a/.github/agents/wind-doc-writer.agent.md b/.github/agents/wind-doc-writer.agent.md deleted file mode 100644 index 750e3c8..0000000 --- a/.github/agents/wind-doc-writer.agent.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -name: 'wind-doc-writer' -description: 'Write and update Wind framework documentation following TailwindCSS patterns and project conventions' -tools: ['read', 'edit', 'create_file', 'search'] ---- - -# Wind Documentation Writer - -Write documentation for Wind framework following TailwindCSS patterns and existing project conventions. - -## Source Code First - -**ALWAYS base documentation on actual source code in `lib/src/`.** - -Before writing ANY documentation: - -1. **Read the implementation** — Find and read the relevant source file: - - Widgets → `lib/src/widgets/` - - Parsers → `lib/src/parser/parsers/` - - Theme → `lib/src/theme/` - - Core → `lib/src/core/` - -2. **Extract from code** — Document what the code ACTUALLY does: - - Supported className values from parser regex/switch cases - - Widget props from constructor parameters - - Default values from code, not assumptions - -3. **Verify examples work** — Code snippets must match implementation behavior - -## Documentation Structure - -**Section Order (Utilities):** -1. H1 Title + Description -2. Table of Contents (MANDATORY) -3. x-preview + code block -4. Basic Usage -5. Quick Reference table -6. Variants -7. Responsive Design -8. Dark Mode -9. Arbitrary Values -10. Customizing Theme -11. Related Documentation - -**Section Order (Widgets):** -1. H1 Title + Description -2. Table of Contents (MANDATORY) -3. x-preview + code block -4. Basic Usage -5. Constructor -6. Props table -7. Layout Modes -8. Event Handling -9. State Variants -10. Styling Examples -11. All Supported Classes -12. Customizing Theme -13. Related Documentation - -## x-preview Components - -```html - -``` - -When adding NEW x-preview or MODIFYING code snippets, add a TODO comment: - -```html - - - -``` - -## Formatting Rules - -- One `#` title per file -- Code blocks use `dart` language tag -- Props table: left-aligned columns, backtick all code values -- Required props show `**Required**` in Default column -- Keep code examples short, realistic, and copy-pasteable -- Related docs at bottom with relative links diff --git a/.github/agents/wind-example-builder.agent.md b/.github/agents/wind-example-builder.agent.md deleted file mode 100644 index aa689a2..0000000 --- a/.github/agents/wind-example-builder.agent.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -name: 'wind-example-builder' -description: 'Build, update, and manage Wind framework example pages for documentation demos' -tools: ['read', 'edit', 'create_file', 'search', 'run_terminal_cmd'] ---- - -# Wind Example Builder - -Build example pages for Wind framework documentation. - -## Path Format Convention - -| Component | Format | Example | -|-----------|--------|---------| -| Folder name | **HYPHENS** | `core-concepts/`, `getting-started/` | -| File name | **UNDERSCORES** | `state_management_overview.dart` | -| Route key | `/{folder-hyphen}/{file_underscore}` | `/core-concepts/state_management_overview` | -| x-preview path | `{folder-hyphen}/{file_underscore}` | `core-concepts/state_management_overview` | -| source attr | `example/lib/pages/{folder-hyphen}/{file_underscore}.dart` | Full path | - -## Workflow - -1. **Scan TODOs:** Find `` comments in `doc/` -2. **Validate paths:** Folder = hyphens, file = underscores -3. **Create page** at `example/lib/pages/{category}/{page_name}.dart` -4. **Register route** in `example/lib/routes.dart` -5. **Remove TODO** from doc file (keep only x-preview tag) - -## Page Template - -```dart -import 'package:flutter/material.dart'; -import 'package:fluttersdk_wind/fluttersdk_wind.dart'; - -class {PageName}ExamplePage extends StatelessWidget { - const {PageName}ExamplePage({super.key}); - - @override - Widget build(BuildContext context) { - return WDiv( - className: 'w-full h-full overflow-y-auto p-4', - scrollPrimary: true, - child: WDiv( - className: 'flex flex-col gap-6 max-w-4xl mx-auto', - children: [ - _buildHeader(), - _buildSection( - title: 'Section Title', - description: 'What this demonstrates', - child: /* Demo widget */, - ), - ], - ), - ); - } - - Widget _buildHeader() { - return WDiv( - className: 'bg-gradient-to-r from-blue-500 to-purple-600 rounded-xl p-6', - child: WText('Page Title', className: 'text-2xl font-bold text-white'), - ); - } - - Widget _buildSection({ - required String title, - required String description, - required Widget child, - }) { - return WDiv( - className: 'flex flex-col gap-4 p-4 bg-white dark:bg-slate-800 rounded-lg shadow-sm', - children: [ - WText(title, className: 'text-lg font-semibold text-slate-900 dark:text-white'), - WText(description, className: 'text-sm text-slate-600 dark:text-slate-400'), - child, - ], - ); - } -} -``` - -## State Prefix Rules - -| Widget | State Support | Notes | -|--------|--------------|-------| -| `WButton` | Built-in | Has internal state management | -| `WInput` | Built-in | Has focus/hover detection | -| `WAnchor` | Provider | Provides state to descendants | -| `WDiv` | Conditional | Auto-wraps ONLY if className contains `hover:`/`focus:`/`active:` | - -## Quality Checklist - -- Page renders without errors -- Demonstrates documented feature accurately -- Uses Wind utilities correctly (className, not inline styles) -- Route registered and accessible -- TODO removed from doc file -- Always include dark mode variants -- Use realistic content, not "Lorem ipsum" diff --git a/.github/agents/wind-ui.agent.md b/.github/agents/wind-ui.agent.md deleted file mode 100644 index 96167db..0000000 --- a/.github/agents/wind-ui.agent.md +++ /dev/null @@ -1,127 +0,0 @@ ---- -name: 'wind-ui' -description: 'Wind framework expert — className patterns, layout rules, widget composition, responsive/dark mode styling' -tools: ['read', 'edit', 'create_file', 'search', 'run_terminal_cmd'] ---- - -# Wind Framework - -Utility-first Flutter UI. Styling via `className` strings → `WindParser` → `WindStyle` → Widget tree. - -## Widgets - -| Widget | Purpose | Key Props | -|--------|---------|-----------| -| `WDiv` | Container/layout | `className`, `child`/`children`, `states`, `scrollPrimary` | -| `WText` | Text | `data`, `className`, `selectable` | -| `WButton` | Button | `child`, `onTap`, `isLoading`, `disabled` | -| `WInput` | Text input | `value`, `onChanged`, `type`, `placeholder` | -| `WSelect` | Dropdown | `options`, `value`, `onChange`, `isMulti`, `searchable`, `onSearch`, `menuClassName` | -| `WCheckbox` | Checkbox | `value`, `onChanged`, `iconClassName` | -| `WImage` | Image | `src` (url/`asset://`), `alt`, `placeholder`, `errorBuilder` | -| `WSvg` | SVG | `src` or `WSvg.string(svgString:)` | -| `WIcon` | Icon | `icon` (IconData), `semanticLabel` | -| `WPopover` | Overlay | `triggerBuilder`, `contentBuilder`, `alignment`, `controller`, `offset`, `maxHeight` | -| `WSpacer` | Spacing | `className` — lightweight SizedBox (`h-*`/`w-*`) | -| `WFormInput` | Validated input | `validator`, `label`, `hint`, `labelClassName`, `errorClassName` | -| `WFormSelect` | Validated select | Same as WSelect + `validator`, `label` | -| `WFormMultiSelect` | Multi-select | `values`, `onMultiChange`, `onCreateOption` | -| `WFormCheckbox` | Validated checkbox | Same as WCheckbox + `validator` | -| `WFormDatePicker` | Date picker | `value`, `onChange`, `validator`, `minDate`, `maxDate` | -| `WAnchor` | State wrapper | `onTap`, `onLongPress`, `isDisabled`, `states` | - -All widgets accept `className` and `states` (Set\). - -## States & Prefixes - -**Interaction:** `hover:`, `focus:`, `disabled:`, `loading:`, `checked:`, `error:`, `open:`, `selected:` - -**Dark mode:** `dark:bg-gray-900 dark:text-white` - -**Responsive (mobile-first):** `sm:` (640), `md:` (768), `lg:` (1024), `xl:` (1280), `2xl:` (1536) - -**Platform:** `mobile:`, `macos:`, `windows:`, `web:`, `ios:`, `android:` - -WDiv auto-wraps in WAnchor when `hover:`/`focus:`/`active:` prefixes are detected. - -## Common Patterns - -### Layout -```dart -WDiv(className: 'flex flex-col md:flex-row gap-4 p-6') -WDiv(className: 'grid grid-cols-2 md:grid-cols-3 gap-4') -WDiv(className: 'wrap gap-2', children: [...]) // Wrapping layout -WDiv(className: 'flex justify-center items-center h-full') -``` - -### Scrollable Content -```dart -WDiv( - className: 'overflow-y-auto max-h-[300px] p-4', - child: content, -) -WDiv( - className: 'overflow-y-auto flex flex-col gap-6 p-4 lg:p-6', - scrollPrimary: true, - children: [/* page content */], -) -``` - -### Card -```dart -WDiv( - className: 'bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6 border border-gray-100 dark:border-gray-700', - children: [ - WText('Title', className: 'text-xl font-bold text-gray-900 dark:text-white'), - WText('Body', className: 'text-sm text-gray-600 dark:text-gray-400 mt-2'), - ], -) -``` - -### Button -```dart -WButton( - className: 'bg-primary hover:bg-green-600 text-white px-4 py-2 rounded-lg disabled:opacity-50', - onTap: () {}, - isLoading: isSubmitting, - child: WText('Submit'), -) -``` - -### Form Input -```dart -WFormInput( - className: 'w-full px-3 py-3 rounded-lg bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 focus:border-primary focus:ring-2 focus:ring-primary/20 error:border-red-500', - label: 'Email', - labelClassName: 'text-sm font-medium text-gray-700 dark:text-gray-300', - errorClassName: 'text-xs text-red-500 mt-1', - validator: (v) => v?.contains('@') == true ? null : 'Invalid email', -) -``` - -### Theme Setup -```dart -WindTheme( - initialData: WindThemeData( - colors: {...WindThemeData.defaultColors, 'primary': {'500': Color(0xFF009E60)}}, - ), - child: MaterialApp(...), -) -``` - -## Key Rules - -1. **Last class wins** — later classes override earlier ones for same property -2. **Spacing scale** — N * 4px: `p-4` = 16px, `gap-2` = 8px -3. **Arbitrary values** — bracket syntax: `w-[200px]`, `text-[#FF0000]` -4. **Opacity shorthand** — `bg-red-500/50`, `text-blue-500/75` -5. **Cache** — WindParser caches results; call `WindParser.clearCache()` in tests - -## Gotchas - -| Issue | Solution | -|-------|----------| -| className typos silently fail | No compile errors — double-check spelling | -| `overflow-y-auto` without height | Add `max-h-*` or parent flex constraint | -| Dark mode missing | Every bg/text/border needs `dark:` variant | -| **`flex-wrap` is a NO-OP** | Use `wrap gap-2` instead. `flex` creates Row/Column which cannot wrap | diff --git a/.github/prompts/release.prompt.md b/.github/prompts/release.prompt.md deleted file mode 100644 index 884d4b9..0000000 --- a/.github/prompts/release.prompt.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -name: 'release' -description: 'Prepare a new release — version bump, changelog, GitHub Release which triggers validate + publish to pub.dev' -agent: 'agent' -argument-hint: 'Target version (e.g. 1.0.0-alpha.5, 1.0.0-beta.1, 1.0.0)' -tools: ['read', 'edit', 'run_terminal_cmd', 'search'] ---- - -## Context - -Run these commands and use the output: - -- `grep 'version:' pubspec.yaml` — current version -- `git branch --show-current` — current branch -- `git tag -l | sort -V | tail -10` — recent git tags -- `gh release list --limit 5` — recent GitHub releases -- `sed -n '/## \[Unreleased\]/,/^## \[/p' CHANGELOG.md | head -40` — unreleased changes -- `git log $(git describe --tags --abbrev=0 2>/dev/null || echo HEAD~20)..HEAD --oneline` — commits since last tag -- `flutter test 2>&1 | tail -3` — test status -- `dart analyze 2>&1 | tail -3` — analyzer status - -## Arguments - -${input:version:Target version to release (e.g. 1.0.0-alpha.5). Leave empty to auto-increment.} - -## Your Task - -Prepare a new release for the **Wind UI** Flutter package. Follow this checklist precisely: - -### Phase 1: Validation - -1. **Branch check** — Must be on `v1` branch. If not, STOP and warn. -2. **Clean tree** — `git status` must show no uncommitted changes. If dirty, STOP and warn. -3. **Tests** — All tests must pass. If failing, STOP and report. -4. **Analyzer** — Zero issues required. If issues, STOP and report. -5. **Version** — Determine the new version from the provided argument or auto-increment. - -### Phase 2: Version Bump - -Update the version string in ALL of these files: - -| File | What to update | -|------|----------------| -| `pubspec.yaml` | `version:` field | -| `CHANGELOG.md` | Move `[Unreleased]` content to `[{version}] - {YYYY-MM-DD}`, add empty `[Unreleased]` above | -| `CLAUDE.md` | `**Version:**` line | -| `doc/getting-started/installation.md` | `fluttersdk_wind: ^{version}` in the yaml code block | - -### Phase 3: Changelog Enhancement - -Review the `[Unreleased]` section and the git log since the last tag: - -1. **Cross-reference** — Ensure every significant commit is reflected in CHANGELOG.md -2. **Missing entries** — Add any commits that introduced features, fixes, or improvements but were not logged -3. **Categorize** using: `### New Features`, `### Bug Fixes`, `### Improvements`, `### Breaking Changes` -4. **Entry format** — `- **Short Title**: One-line description` -5. **Date** — Use today's date in `YYYY-MM-DD` format - -### Phase 4: README Sync - -Check README.md for version-specific content that needs updating (badges, install examples, outdated code). - -### Phase 5: Local Verification - -Run all checks locally — ALL must pass: - -1. `dart format --set-exit-if-changed .` — must be clean -2. `dart analyze` — must be zero issues -3. `flutter test` — must all pass -4. `dart pub publish --dry-run` — must be zero warnings -5. Review all changed files with `git diff` - -If dry-run fails, STOP and fix before proceeding. - -### Phase 6: Commit & Push - -1. Stage all modified files -2. Create a single commit: `chore(release): {version}` -3. Push to remote: `git push` - -### Phase 7: Create GitHub Release - -Create a GitHub Release using `gh` CLI: - -```bash -gh release create {version} \ - --target v1 \ - --title "v{version}" \ - [--prerelease] \ - --notes "{changelog content}" -``` - -- Contains `alpha`, `beta`, or `rc` → add `--prerelease` flag -- After creating, watch the publish workflow: `gh run list --workflow=publish.yml --limit 1` - -### Output - -Present a summary with: GitHub Release URL, changed files, changelog counts, local verification results, pub.dev publish status. diff --git a/.github/scripts/sync-cc-to-copilot.sh b/.github/scripts/sync-cc-to-copilot.sh index 0a9b604..0fcf005 100755 --- a/.github/scripts/sync-cc-to-copilot.sh +++ b/.github/scripts/sync-cc-to-copilot.sh @@ -15,12 +15,10 @@ for rule in "$RULES_DIR"/*.md; do name=$(basename "$rule" .md) target="$INSTRUCTIONS_DIR/${name}.instructions.md" - # Extract frontmatter fields + # Extract path: from frontmatter path_glob=$(sed -n '/^---$/,/^---$/{ /^path:/{ s/^path: *"*\(.*\)"*/\1/; p; } }' "$rule") # Extract body (everything after second ---) - body=$(sed '1,/^---$/{ /^---$/!d; }; /^---$/{ N; d; }' "$rule" | sed '1,/^---$/d') - # Simpler: skip first 3 lines (---, path:, ---) then take the rest body=$(awk 'BEGIN{c=0} /^---$/{c++; next} c>=2{print}' "$rule") # Generate human-readable name from filename From d0a29fc5cd9eff33fa424f68ae96c954d1c491a1 Mon Sep 17 00:00:00 2001 From: Anilcan Cakir Date: Tue, 31 Mar 2026 20:44:16 +0300 Subject: [PATCH 3/3] chore: remove version from Copilot instructions --- .github/copilot-instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index d54b521..e5f874b 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2,7 +2,7 @@ Utility-first Flutter UI plugin. Translates `className` strings (Tailwind syntax) into Flutter widget trees via modular parsing architecture. -**Version:** 1.0.0-alpha.4 · **Branch:** `v1` (master = v0, do NOT touch) · **Dart:** >=3.4.0 · **Flutter:** >=3.27.0 +**Dart:** >=3.4.0 · **Flutter:** >=3.27.0 ## Architecture