diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..2c3aab86 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: Flutter CI + +on: + pull_request: + branches: + - main + paths-ignore: + - docs/** + - docs.json + + push: + branches: + - main + paths-ignore: + - docs/** + - docs.json + +# Cancel any in-progress runs of the same workflow for the same PR/branch. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + uses: btwld/dart-actions/.github/workflows/ci.yml@main + with: + min_coverage: 80 \ No newline at end of file diff --git a/.github/workflows/pr-title_check.yml b/.github/workflows/pr-title_check.yml new file mode 100644 index 00000000..10fa05a4 --- /dev/null +++ b/.github/workflows/pr-title_check.yml @@ -0,0 +1,10 @@ +# .github/workflows/pr-title-check.yml.yml +name: "Pull Request Title Check" + +on: + pull_request_target: + types: [opened, edited, synchronize] + +jobs: + check-title: + uses: btwld/dart-actions/.github/workflows/pr-title-check.yml@main \ No newline at end of file diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml deleted file mode 100644 index 16bebf8c..00000000 --- a/.github/workflows/pr.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: "Pull-Request Check" - -on: - pull_request_target: - types: - - opened - - edited - - synchronize - -jobs: - main: - name: Validate PR title - runs-on: ubuntu-latest - steps: - - uses: amannn/action-semantic-pull-request@v5.5.3 - id: lint_pr_title - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - uses: marocchino/sticky-pull-request-comment@v2 - # When the previous steps fails, the workflow would stop. By adding this - # condition you can continue the execution with the populated error message. - if: always() && (steps.lint_pr_title.outputs.error_message != null) - with: - header: pr-title-lint-error - message: | - Hey there and thank you for opening this pull request! πŸ‘‹πŸΌ - - We require pull request titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/) and it looks like your proposed title needs to be adjusted. - - Details: - - ``` - ${{ steps.lint_pr_title.outputs.error_message }} - ``` - - # Delete a previous comment when the issue has been resolved - - if: ${{ steps.lint_pr_title.outputs.error_message == null }} - uses: marocchino/sticky-pull-request-comment@v2 - with: - header: pr-title-lint-error - delete: true \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..a0f6db84 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,15 @@ +name: Publish to pub.dev + +on: + push: + tags: + - 'v[0-9]+.[0-9]+.[0-9]+*' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + publish: + uses: btwld/dart-actions/.github/workflows/publish.yml@main diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml deleted file mode 100644 index a4d8688d..00000000 --- a/.github/workflows/release-please.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Prepare Release PR - -on: - workflow_dispatch: - inputs: - version: - description: "Version to release (e.g., 2.0.0)" - required: false - default: "" - -permissions: - contents: write - pull-requests: write - -jobs: - release-please: - name: Run release-please - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Check version input - id: check-version - run: | - if [[ -z "${{ github.event.inputs.version }}" ]]; then - echo "Version input is empty. Skipping commit." - exit 0 - fi - echo "Version input provided: ${{ github.event.inputs.version }}" - echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV - - - name: Create empty commit - if: ${{ env.VERSION }} - run: | - git config --global user.name "${{ github.actor }}" - git config --global user.email "${{ github.actor }}@users.noreply.github.com" - git commit --allow-empty -m "chore: release ${{ env.VERSION }}" -m "Release-As: ${{ env.VERSION }}" - git push origin HEAD - - - uses: google-github-actions/release-please-action@v4 - with: - release-type: dart - skip-github-pull-request: false - skip-labeling: true - skip-github-release: false - config-file: release-please-config.json \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index dfde7dbb..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Publish to pub.dev - -on: - push: - tags: - - 'v[0-9]+.[0-9]+.[0-9]+*' - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - publish: - name: Publish to pub.dev - environment: Production - runs-on: ubuntu-latest - permissions: - id-token: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Flutter - uses: subosito/flutter-action@v2 - with: - channel: 'stable' - flutter-version: 3.35.0 - cache: true - - - name: Install root dependencies - run: flutter pub get && cd demo && flutter pub get - - - name: Analyze project - run: flutter analyze - - - name: Run tests - run: flutter test - - - name: Publish - dry run - run: dart pub publish --dry-run - - - name: Publish to pub.dev (OIDC) - run: dart pub publish --force diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml deleted file mode 100644 index 10a9839c..00000000 --- a/.github/workflows/test.yaml +++ /dev/null @@ -1,73 +0,0 @@ -name: Flutter CI - -on: - pull_request: - branches: - - main - paths-ignore: - - docs/** - - docs.json - - push: - branches: - - main - paths-ignore: - - docs/** - - docs.json - -# Cancel any in-progress runs of the same workflow for the same PR/branch. -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - test: - name: Run Tests - runs-on: ubuntu-latest - permissions: - pull-requests: write - strategy: - # Keep running other jobs in the matrix even if one fails. - fail-fast: false - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Flutter - uses: subosito/flutter-action@v2 - with: - channel: 'stable' - flutter-version: 3.35.0 - cache: true - - - name: Install root dependencies - run: flutter pub get && cd demo && flutter pub get - - - name: Analyze root project - run: flutter analyze - - - name: Install DCM - uses: CQLabs/setup-dcm@v2 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Run DCM - run: dcm analyze . - shell: bash - - - name: Run root tests - run: flutter test --coverage - - - name: Setup LCOV - uses: hrishikesh-kadam/setup-lcov@v1 - with: - ref: v2.3 - - - name: Report Code Coverage - uses: zgosalvez/github-actions-report-lcov@v4 - with: - coverage-files: coverage/lcov.info - minimum-coverage: 5 - artifact-name: code-coverage-report - github-token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/BUTTON_STYLING_GUIDE.md b/BUTTON_STYLING_GUIDE.md deleted file mode 100644 index 2cd5349b..00000000 --- a/BUTTON_STYLING_GUIDE.md +++ /dev/null @@ -1,277 +0,0 @@ -# RemixButton Fluent API Styling Guide - -## Overview - -The `RemixButtonStyle` class provides a comprehensive three-tier fluent API for styling buttons, from simple property changes to complex styling scenarios. - -## Three-Tier API Approach - -### 🎯 **Tier 1: Individual Property Helpers** (Most Common) - -Use these methods for simple, single property changes. They're the most discoverable and readable approach. - -```dart -RemixButtonStyle() - // Label styling - .labelColor(Colors.white) - .labelFontSize(16.0) - .labelFontWeight(FontWeight.bold) - .labelLetterSpacing(0.5) - - // Icon styling - .iconColor(Colors.white) - .iconSize(20.0) - .iconOpacity(0.9) - - // Spinner styling - .spinnerIndicatorColor(Colors.white) - .spinnerSize(16.0) - .spinnerStrokeWidth(2.0) - .spinnerFast() - - // Container styling (via mixins) - .color(Colors.blue) - .borderRadiusAll(Radius.circular(8)) - .paddingAll(16.0) -``` - -**Available Label Helpers:** -- `labelColor(Color)` - Sets text color -- `labelFontSize(double)` - Sets font size -- `labelFontWeight(FontWeight)` - Sets font weight -- `labelFontStyle(FontStyle)` - Sets italic/normal -- `labelLetterSpacing(double)` - Sets letter spacing -- `labelWordSpacing(double)` - Sets word spacing -- `labelHeight(double)` - Sets line height -- `labelDecoration(TextDecoration)` - Sets underline, strikethrough, etc. -- `labelDecorationColor(Color)` - Sets decoration color -- `labelFontFamily(String)` - Sets font family - -**Available Icon Helpers:** -- `iconColor(Color)` - Sets icon color -- `iconSize(double)` - Sets icon size -- `iconOpacity(double)` - Sets icon opacity -- `iconWeight(double)` - Sets icon weight (variable fonts) -- `iconGrade(double)` - Sets icon grade (Material Icons) -- `iconFill(double)` - Sets icon fill (Material Icons) -- `iconOpticalSize(double)` - Sets optical size -- `iconBlendMode(BlendMode)` - Sets blend mode -- `iconShadows(List)` - Sets shadows - -**Available Spinner Helpers:** -- `spinnerIndicatorColor(Color)` - Sets spinner indicator color -- `spinnerTrackColor(Color)` - Sets spinner track color -- `spinnerSize(double)` - Sets spinner size -- `spinnerStrokeWidth(double)` - Sets indicator stroke width -- `spinnerTrackStrokeWidth(double)` - Sets track stroke width -- `spinnerDuration(Duration)` - Sets animation duration -- `spinnerFast()` - Sets to 500ms duration (convenience) -- `spinnerNormal()` - Sets to 1000ms duration (convenience) -- `spinnerSlow()` - Sets to 1500ms duration (convenience) - -### 🎨 **Tier 2: TextStyleMix Helper** (Multiple Properties) - -When you need to set multiple text properties at once, use `labelTextStyle()` with a `TextStyleMix`: - -```dart -RemixButtonStyle() - .labelTextStyle(TextStyleMix( - color: Colors.white, - fontSize: 18.0, - fontWeight: FontWeight.bold, - letterSpacing: 0.5, - height: 1.2, - decoration: TextDecoration.underline, - )) - .iconColor(Colors.white) - .iconSize(22.0) -``` - -**When to Use Tier 2:** -- Setting 3+ text properties at once -- Need to pass a pre-built `TextStyleMix` -- Want type safety with Mix's styling system -- Building reusable style objects - -### ⚑ **Tier 3: Full Control** (Complex Scenarios) - -For advanced text features or complex styling needs, use the full `label()` and `icon()` methods: - -```dart -RemixButtonStyle() - .label( - TextStyler() - .style(TextStyleMix( - color: Colors.white, - fontSize: 16.0, - fontWeight: FontWeight.bold, - )) - .uppercase() // Text transformations - .maxLines(2) // Layout constraints - .overflow(TextOverflow.ellipsis) - .textAlign(TextAlign.center) - ) - .icon(IconStyler( - color: Colors.white, - size: 20.0, - shadows: [ShadowMix.elevation(4)], - blendMode: BlendMode.multiply, - )) -``` - -**When to Use Tier 3:** -- Need text transformations (uppercase, lowercase, etc.) -- Complex layout constraints (maxLines, overflow, alignment) -- Advanced icon features (complex shadows, blend modes) -- Conditional styling with builders - -## Migration from Old API - -### Before (Verbose) -```dart -RemixButtonStyle() - .label( - TextStyler() - .color(Colors.white) - .fontSize(16.0) - ) - .icon(IconStyler( - color: Colors.white, - size: 20.0, - )) -``` - -### After (Clean) -```dart -RemixButtonStyle() - .labelColor(Colors.white) - .labelFontSize(16.0) - .iconColor(Colors.white) - .iconSize(20.0) -``` - -## Common Patterns - -### Primary Button -```dart -static RemixButtonStyle get primary => RemixButtonStyle() - .color(Colors.blue) - .labelColor(Colors.white) - .labelFontSize(16.0) - .labelFontWeight(FontWeight.w600) - .iconColor(Colors.white) - .iconSize(20.0) - .borderRadiusAll(Radius.circular(8)) - .paddingX(16.0) - .paddingY(12.0); -``` - -### Outline Button -```dart -static RemixButtonStyle get outline => RemixButtonStyle() - .color(Colors.transparent) - .labelColor(Colors.blue) - .labelFontWeight(FontWeight.w500) - .iconColor(Colors.blue) - .borderAll(color: Colors.blue, width: 2.0) - .borderRadiusAll(Radius.circular(8)) - .onHovered(RemixButtonStyle() - .color(Colors.blue.withOpacity(0.05))); -``` - -### Ghost/Text Button -```dart -static RemixButtonStyle get ghost => RemixButtonStyle() - .color(Colors.transparent) - .labelColor(Colors.grey.shade700) - .iconColor(Colors.grey.shade600) - .onHovered(RemixButtonStyle() - .color(Colors.grey.shade50) - .labelColor(Colors.grey.shade900)); -``` - -### Complex Typography -```dart -static RemixButtonStyle get typography => RemixButtonStyle() - .color(Colors.indigo) - .labelTextStyle(TextStyleMix( - color: Colors.white, - fontSize: 16.0, - fontWeight: FontWeight.w600, - letterSpacing: 0.2, - height: 1.3, - fontStyle: FontStyle.normal, - )) - .iconColor(Colors.white.withOpacity(0.9)) - .iconSize(20.0); -``` - -### Loading Button with Spinner -```dart -static RemixButtonStyle get loading => RemixButtonStyle() - .color(Colors.blue) - .labelColor(Colors.white.withOpacity(0.7)) - .iconColor(Colors.white.withOpacity(0.7)) - .spinnerIndicatorColor(Colors.white) - .spinnerSize(16.0) - .spinnerStrokeWidth(2.0) - .spinnerFast(); // 500ms animation -``` - -## Method Chaining Best Practices - -### βœ… Good: Logical Grouping -```dart -RemixButtonStyle() - // Background and structure - .color(Colors.blue) - .borderRadiusAll(Radius.circular(8)) - .paddingX(16.0) - .paddingY(12.0) - - // Text styling - .labelColor(Colors.white) - .labelFontSize(16.0) - .labelFontWeight(FontWeight.w600) - - // Icon styling - .iconColor(Colors.white) - .iconSize(20.0) - - // Interactive states - .onHovered(RemixButtonStyle().color(Colors.blue.shade700)); -``` - -### ❌ Avoid: Mixing API Tiers Unnecessarily -```dart -// Don't mix tiers when tier 1 is sufficient -RemixButtonStyle() - .labelColor(Colors.white) // Tier 1 - .labelTextStyle(TextStyleMix( // Tier 2 - unnecessary here - fontSize: 16.0, - )) -``` - -## Performance Considerations - -- **All tiers have identical runtime performance** - they're syntactic sugar over the same underlying implementation -- Helper methods create the same `TextStyler`/`IconStyler` objects internally -- Use the tier that best matches your use case for code clarity -- Method chaining creates new immutable instances (expected Flutter pattern) - -## When to Use Which Tier - -| Scenario | Recommended Tier | Example | -|----------|------------------|---------| -| Single property change | Tier 1 | `.labelColor(Colors.red)` | -| 2-3 simple properties | Tier 1 | `.labelColor().labelFontSize()` | -| 3+ text properties | Tier 2 | `.labelTextStyle(TextStyleMix(...))` | -| Text transformations | Tier 3 | `.label(TextStyler().uppercase())` | -| Complex layout constraints | Tier 3 | `.label(TextStyler().maxLines(2))` | -| Reusable style objects | Tier 2/3 | Create `TextStyleMix` variables | - -## Examples in Action - -See `lib/src/components/button/button_style_examples.dart` for comprehensive examples of all patterns and use cases. - -For Fortal-compliant buttons, see `lib/src/components/button/radix_button_styles.dart` which uses these patterns throughout all 6 button variants. diff --git a/FORTAL_VARIANTS.md b/FORTAL_VARIANTS.md deleted file mode 100644 index 544fc3a1..00000000 --- a/FORTAL_VARIANTS.md +++ /dev/null @@ -1,550 +0,0 @@ -# Fortal Variant System Implementation Plan - -## Analysis Summary - -After analyzing the `component_tokens_ref.json` file, I've discovered that the Fortal UI variant system is **NOT universal** - each component has different token mappings for the same variant names. - -## Key Findings - -### 1. Variants Have Different Values Per Component - -The same variant name uses different tokens across components: - -#### Example: "Solid" Variant -- **Button/IconButton**: - - Background: `{accent}[9]` β†’ `{accent}[10]` on hover - - Text: `--accent-contrast` - - Focus ring: `--focus-a8` - -- **Badge**: - - Background: `{accent}[9]` (no hover state) - - Text: `--accent-contrast` - - No focus ring - -- **Code**: - - Background: `{accent}[9]` - - Text: `--accent-contrast` - -- **Spinner**: - - No solid variant (only default with stroke `{accent}[9]`) - -#### Example: "Soft" Variant -- **Button**: - - Background: `{accent}[3]` β†’ `{accent}[4]` hover β†’ `{accent}[5]` active - - Text: `{accent}[11]` - - Border: `{accent}[6]` β†’ `{accent}[7]` hover - -- **Checkbox**: - - Background: `{accent}[3]` (no hover/active states) - - Border: `{accent}[6]` (no hover) - - Check color: `{accent}[11]` - -- **TextField**: - - Background: `{accent}[3]` - - Text: `{accent}[12]` (different from button!) - - Placeholder: `{accent}[10]` - - Border: `{accent}[6]` β†’ `{accent}[8]` on focus - -- **Progress**: - - Track: `{accent}[4]` (completely different structure) - - Indicator: `{accent}[9]` - -### 2. Components Support Different Variant Subsets - -| Component | Supported Variants | Count | -|-----------|-------------------|--------| -| Button/IconButton | solid, soft, surface, outline, ghost, classic | 6 | -| Badge | solid, soft, surface, outline | 4 | -| Card | surface, classic, ghost | 3 | -| Checkbox/Radio | classic, surface, soft | 3 | -| Switch | classic, surface, soft | 3 | -| Progress | classic, surface, soft | 3 | -| Slider | classic, surface, soft | 3 | -| TextField/TextArea | classic, surface, soft | 3 | -| Spinner | (none - just default) | 0 | -| Select | Trigger: classic, surface, soft, ghost / Content: solid, soft | 4+2 | - -### 3. Component-Specific Properties - -Different components require completely different style properties: - -- **Buttons**: background, text, border, focusRing -- **Progress**: track, indicator (both require BoxStyler wrappers) -- **Slider**: track, range (Paint objects), thumb (BoxStyler) -- **Checkbox**: indicatorContainer, indicator, label, container -- **Switch**: track, thumb, container (state variants handled via .onVariant()) -- **Select**: Separate Trigger and Content variants - -**Important**: All color tokens must be wrapped in appropriate Styler objects: -- Colors: `BoxStyler(decoration: BoxDecorationMix(color: token))` -- Text colors: `TextStyler(color: token)` -- Icon colors: `IconStyler(color: token)` - -## Recommended Implementation - -### Approach: Component-Specific Variant Factories - -Since variants are NOT universal, each component needs its own variant factory class. - -### Implementation Structure - -```dart -// 1. Keep existing FortalTokens as-is (already done) -// Provides the building blocks for all variants - -// 2. Create component-specific factory classes -// Each implements only the variants that make sense for that component - -// Example: Button (all 6 variants) -class FortalButtonStyles { - static RemixButtonStyle solid({int size = 2}) { - // Uses {accent}[9], hover {accent}[10], --accent-contrast - } - static RemixButtonStyle soft({int size = 2}) { - // Uses {accent}[3], hover {accent}[4], active {accent}[5] - } - static RemixButtonStyle surface({int size = 2}) { ... } - static RemixButtonStyle outline({int size = 2}) { ... } - static RemixButtonStyle ghost({int size = 2}) { ... } - static RemixButtonStyle classic({int size = 2}) { ... } -} - -// Example: Checkbox (only 3 variants) - UPDATED WITH DIRECT SCALE TOKENS -class FortalCheckboxStyles { - static RemixCheckboxStyle classic({int size = 2}) { - return RemixCheckboxStyle() - .indicatorContainer(BoxStyler( - decoration: BoxDecorationMix( - color: FortalTokens.colorSurface(), - border: BoxBorderMix.all( - color: FortalTokens.gray7(), - width: FortalTokens.borderWidth1(), - ), - ), - )) - .indicatorColor(FortalTokens.gray12()); - } - - static RemixCheckboxStyle surface({int size = 2}) { - return RemixCheckboxStyle() - .indicatorContainer(BoxStyler( - decoration: BoxDecorationMix( - color: FortalTokens.accentSurface(), - border: BoxBorderMix.all( - color: FortalTokens.accent6(), - width: FortalTokens.borderWidth1(), - ), - ), - )) - .indicatorColor(FortalTokens.accent11()); - } - - static RemixCheckboxStyle soft({int size = 2}) { - return RemixCheckboxStyle() - .indicatorContainer(BoxStyler( - decoration: BoxDecorationMix( - color: FortalTokens.accent3(), - border: BoxBorderMix.all( - color: FortalTokens.accent6(), - width: FortalTokens.borderWidth1(), - ), - ), - )) - .indicatorColor(FortalTokens.accent11()); - } - // No solid, outline, or ghost variants! -} - -// Example: Progress (different properties entirely) - UPDATED WITH DIRECT SCALE TOKENS -class FortalProgressStyles { - static RemixProgressStyle classic({int size = 2}) { - return RemixProgressStyle() - .track(BoxStyler( - decoration: BoxDecorationMix( - color: FortalTokens.accentTrack(), // --accent-track (gray6) - ), - )) - .indicator(BoxStyler( - decoration: BoxDecorationMix( - color: FortalTokens.accentIndicator(), // --accent-indicator (accent9) - ), - )); - } - - static RemixProgressStyle soft({int size = 2}) { - return RemixProgressStyle() - .track(BoxStyler( - decoration: BoxDecorationMix( - color: FortalTokens.accent4(), // Direct scale access - ), - )) - .indicator(BoxStyler( - decoration: BoxDecorationMix( - color: FortalTokens.accent9(), // Direct scale access - ), - )); - } -} - -// Example: Switch - UPDATED WITH DIRECT SCALE TOKENS -class FortalSwitchStyles { - static RemixSwitchStyle classic({int size = 2}) { - return RemixSwitchStyle() - .trackColor(FortalTokens.colorSurface()) - .thumbColor(FortalTokens.gray12()) - .onVariant('checked', RemixSwitchStyle() - .trackColor(FortalTokens.accentIndicator()) // accent9 - ); - } - - static RemixSwitchStyle soft({int size = 2}) { - return RemixSwitchStyle() - .trackColor(FortalTokens.accent3()) - .thumbColor(FortalTokens.colorSurface()) - .onVariant('checked', RemixSwitchStyle() - .trackColor(FortalTokens.accent9()) - ); - } - // No separate "checkedTrack" or "checkedThumb" properties! - // State variants are handled via .onVariant() method -} - -// Example: Slider - UPDATED WITH DIRECT SCALE TOKENS -class FortalSliderStyles { - static RemixSliderStyle classic({int size = 2}) { - return RemixSliderStyle() - .trackColor(FortalTokens.accentTrack()) // gray6 - .rangeColor(FortalTokens.accentIndicator()) // accent9 - .thumbColor(FortalTokens.colorSurface()); - } - - static RemixSliderStyle soft({int size = 2}) { - return RemixSliderStyle() - .trackColor(FortalTokens.accent4()) - .rangeColor(FortalTokens.accent9()) - .thumbColor(FortalTokens.colorSurface()); - } - // Note: track and range use Paint objects, not BoxStyler - // Use .trackColor() and .rangeColor() convenience methods -} -``` - -### Why NOT a Shared Variant Config? - -A shared `VariantConfig` class would be incorrect because: -1. The same variant name has different token values per component -2. Components have different style properties (background vs track/thumb) -3. Not all components support all variants -4. Would create confusion and type-safety issues - -### Size Config Pattern - -The existing `_ButtonSizeConfig` pattern is good for sizes because: -- Size properties are consistent (height, padding, fontSize, etc.) -- All size variants share the same structure -- Can be reused across components with similar sizing needs - -But this pattern does NOT work for variants because variants change: -- Different properties per component -- Different token mappings per component -- Different state behaviors (hover, active, focus) - -## Implementation Priority - -1. **Already Done**: Button component with all 6 variants βœ“ -2. **High Priority** (most commonly used): - - IconButton (similar to Button) - - TextField/TextArea - - Checkbox/Radio - - Select -3. **Medium Priority**: - - Badge - - Card - - Switch - - Slider -4. **Low Priority**: - - Progress - - Spinner - - Table - - Tabs - - Code - -## Token Mapping Source of Truth - -Use `/Users/leofarias/bitwild/remix/lib/src/radix/colors/component_tokens_ref.json` as the authoritative source for: -- Which variants each component supports -- Exact token mappings for each variant -- State variations (hover, active, focus) -- Component-specific properties - -## Benefits of This Approach - -1. **Accuracy**: Matches actual Fortal UI behavior -2. **Type Safety**: Each component gets exactly the variants it needs -3. **Clarity**: No confusion about which variants are available -4. **Maintainability**: Easy to update individual components -5. **Flexibility**: Can add new variants per component as needed -6. **Documentation**: Self-documenting which variants exist per component - -## Critical Implementation Notes - -### Available FortalTokens (CORRECTED) - -**βœ… Token Constants That Require () to Get Reference Types:** -- **Accent Scale**: `accent1()` through `accent12()` - Full 12-step accent color scale -- **Gray Scale**: `gray1()` through `gray12()` - Full 12-step gray color scale -- **Alpha Scale**: `accentA3()`, `accentA4()`, `accentA8()` - Common alpha transparency steps -- **Functional Color Tokens**: `colorBackground()`, `colorSurface()`, `colorPanelSolid()`, `colorPanelTranslucent()`, `colorOverlay()` -- **Accent Functional**: `accentSurface()`, `accentIndicator()`, `accentTrack()`, `accentContrast()` -- **Focus Tokens**: `focus8()`, `focusA8()` -- **Space Tokens**: `space1()` through `space9()`, `borderWidth1()`, `borderWidth2()`, `focusRingWidth()`, `focusRingOffset()` -- **Radius Tokens**: `radius1()` through `radius6()`, `radiusFull()` - -**βœ… Function Constants That Return Flutter Types:** -- `fontWeightRegular()`, `fontWeightMedium()`, `fontWeightBold()` - Return `FontWeight` -- `transitionFast()`, `transitionSlow()` - Return `Duration` - -**Why () is Required:** -```dart -// Token constants return token objects -FortalTokens.accent9 // Returns ColorToken (not usable in styles) - -// Calling () returns reference types that implement interfaces -FortalTokens.accent9() // Returns ColorRef (implements Color, usable in styles) -FortalTokens.space3() // Returns SpaceRef (implements double, usable as spacing) -FortalTokens.radius2() // Returns RadiusRef (implements Radius, usable for borders) -``` - -**❌ Removed Variant-Specific Tokens (NO LONGER EXIST):** -- `solidBackground()`, `softBackground()`, `surfaceBackground()`, etc. -- `solidText()`, `softText()`, `surfaceText()`, etc. -- `solidFocusRing()`, `softFocusRing()`, `surfaceFocusRing()`, etc. -- **Use direct scale tokens instead**: `accent9()`, `accent11()`, `focusA8()`, etc. - -### Style Method Patterns (CORRECTED) - -1. **All color tokens MUST be wrapped in Styler objects:** - - Background colors: `BoxStyler(decoration: BoxDecorationMix(color: token))` - - Text colors: `TextStyler(color: token)` - - Icon colors: `IconStyler(color: token)` - - Paint objects (Slider): Use convenience methods like `.trackColor()`, `.rangeColor()` - -2. **Component Property Names (Actual vs. Conceptual):** - - βœ… **Progress**: `.track()`, `.indicator()` (both need BoxStyler) - - βœ… **Checkbox**: `.indicatorContainer()` (box), `.indicator()` (check) - - βœ… **Radio**: `.indicatorContainer()` (outer ring), `.indicator()` (inner fill) - - βœ… **Switch**: `.track()`, `.thumb()` only - use `.onVariant('checked', ...)` for state - - βœ… **Slider**: `.trackColor()` (background rail), `.rangeColor()` (filled portion), `.thumbColor()` - -3. **State Handling:** - - Hover/focus states: Use `.onHovered()`, `.onFocused()` methods - - Checked states: Use `.onVariant('checked', style)` method - - Active states: Use `.onPressed()` or `.onVariant('active', style)` - -### Common Mistakes to Avoid - -❌ **WRONG**: Using removed variant-specific tokens: -```dart -FortalTokens.softBackground() // ❌ Removed - no longer exists -FortalTokens.classicBorder() // ❌ Removed - no longer exists -FortalTokens.solidText() // ❌ Removed - no longer exists -``` - -βœ… **CORRECT**: Use direct scale tokens: -```dart -FortalTokens.accent3() // βœ… Direct access to accent step 3 -FortalTokens.gray7() // βœ… Direct access to gray step 7 -FortalTokens.accentContrast() // βœ… For contrast text on accent9 -``` - -❌ **WRONG**: Direct token assignment without Styler wrappers: -```dart -.track(FortalTokens.accentTrack()) // ❌ Missing BoxStyler wrapper -``` - -βœ… **CORRECT**: Wrap tokens in appropriate Stylers: -```dart -.track(BoxStyler(decoration: BoxDecorationMix(color: FortalTokens.accentTrack()))) -``` - -❌ **WRONG**: Checkbox `.box()` and `.check()` methods (don't exist) -βœ… **CORRECT**: Checkbox `.indicatorContainer()` and `.indicator()` - -❌ **WRONG**: Switch `.checkedTrack()` and `.checkedThumb()` (don't exist) -βœ… **CORRECT**: Switch `.onVariant('checked', RemixSwitchStyle().trackColor(...))` - -❌ **WRONG**: Function vs constant confusion: -```dart -FortalTokens.borderWidth1 // ❌ Missing parentheses -FortalTokens.fontWeightMedium() // ❌ Unnecessary parentheses -``` - -βœ… **CORRECT**: Functions need parentheses, constants don't: -```dart -FortalTokens.borderWidth1() // βœ… Function call -FortalTokens.fontWeightMedium // βœ… Constant access -``` - -## Size Method Refactoring Implementation Plan - -### CRITICAL: Remove _SizeConfig Pattern and Add Composable Size Methods - -The current _SizeConfig pattern violates Mix principles by mixing size concerns with variant styling. We need to refactor to make sizing orthogonal and composable. - -### Current Problem - -```dart -// ❌ WRONG: Size parameter in variant methods -FortalButtonStyles.solid(size: 2) // Couples size with variant - -// ❌ WRONG: _SizeConfig storing wrong types -class _ButtonSizeConfig { - final Radius radius; // Type mismatch - should be RadiusRef - const _ButtonSizeConfig({ - required this.radius, // Gets FortalTokens.radius2() which returns RadiusRef - }); -} -``` - -### Target Solution - -```dart -// βœ… CORRECT: Composable size and variant methods -FortalButtonStyles.solid().size2() // Size and variant are orthogonal -FortalButtonStyles.soft().size1() // Any combination possible -``` - -### Implementation Steps - -#### Phase 1: Button Component (Pattern Template) - -1. **Add size methods to FortalButtonStyles**: - ```dart - class FortalButtonStyles { - // Remove size parameter from all variant methods - static RemixButtonStyle solid() { ... } - static RemixButtonStyle soft() { ... } - - // Add composable size methods - static RemixButtonStyle size1() { - return RemixButtonStyle() - .height(32.0) - .paddingHorizontal(FortalTokens.space3()) - .paddingVertical(FortalTokens.space2()) - .borderRadiusAll(FortalTokens.radius2()) - .text(TextStyler().fontSize(12.0)); - } - - static RemixButtonStyle size2() { - return RemixButtonStyle() - .height(40.0) - .paddingHorizontal(FortalTokens.space4()) - .paddingVertical(FortalTokens.space3()) - .borderRadiusAll(FortalTokens.radius3()) - .text(TextStyler().fontSize(14.0)); - } - - static RemixButtonStyle size3() { - return RemixButtonStyle() - .height(48.0) - .paddingHorizontal(FortalTokens.space5()) - .paddingVertical(FortalTokens.space4()) - .borderRadiusAll(FortalTokens.radius4()) - .text(TextStyler().fontSize(16.0)); - } - } - ``` - -2. **Remove _ButtonSizeConfig class entirely** - -3. **Update variant methods to not use size**: - ```dart - static RemixButtonStyle solid() { - return RemixButtonStyle() - .color(FortalTokens.accent9()) - .text(TextStyler().color(FortalTokens.accentContrast())) - // No size-related properties here - .onHovered(RemixButtonStyle().color(FortalTokens.accent10())); - } - ``` - -#### Phase 2: All Remaining Components (11 total) - -Apply the same pattern to each component: - -**High Priority** (most used): -1. **IconButton** - Similar to Button, 3 sizes -2. **TextField** - 3 sizes (height, padding, fontSize, radius) -3. **Checkbox** - 3 sizes (container size, check size) -4. **Radio** - 3 sizes (container size, dot size) -5. **Select** - 3 sizes (trigger height, content padding) - -**Medium Priority**: -6. **Switch** - 3 sizes (track width/height, thumb size) -7. **Slider** - 3 sizes (thumb size, track height) -8. **Badge** - 3 sizes (height, padding, fontSize) - -**Lower Priority**: -9. **Progress** - 3 sizes (track height, border radius) -10. **Spinner** - 3 sizes (diameter, stroke width) -11. **Card** - 3 sizes (padding, border radius) - -#### Phase 3: Update Usage Patterns - -**Examples and Tests**: -```dart -// Old pattern (remove) -RemixButton(style: FortalButtonStyles.solid(size: 2)) - -// New pattern (implement) -RemixButton(style: FortalButtonStyles.solid().size2()) -``` - -### Size Configuration Standards - -Each component should support 3 standard sizes: - -**Size 1 (Small)**: -- Compact forms, toolbars, dense layouts -- Smaller padding, font size, dimensions - -**Size 2 (Medium - Default)**: -- Standard forms, most common use case -- Balanced dimensions for general use - -**Size 3 (Large)**: -- Prominent CTAs, accessibility needs -- Larger touch targets, increased visibility - -### Critical Implementation Rules - -1. **Remove ALL _SizeConfig classes** - They store wrong types and mix concerns -2. **Remove size parameters** from ALL variant methods -3. **Size methods return partial styles** that can be composed -4. **Use direct token calls** with () in size methods: - ```dart - .paddingHorizontal(FortalTokens.space4()) // βœ… Returns SpaceRef - .borderRadiusAll(FortalTokens.radius3()) // βœ… Returns RadiusRef - ``` - -### Next Steps - -1. βœ… Review this plan (COMPLETED - corrected implementation patterns) -2. βœ… **System Simplified** - Removed variant-specific tokens, added direct scale tokens -3. βœ… **Button Updated** - Uses direct scale tokens: `accent9()`, `accent11()`, etc. -4. **CURRENT PRIORITY**: Implement size method refactoring: - - Start with Button component as template pattern - - Remove _ButtonSizeConfig class - - Add .size1(), .size2(), .size3() methods - - Remove size parameter from .solid(), .soft(), etc. - - Test composition: `FortalButtonStyles.solid().size2()` -5. **Next**: Apply same pattern to remaining 10 components -6. **Finally**: Update all examples and test compilation - -## βœ… **Simplified Token System Complete** - -The Fortal token system is now simplified and more maintainable: -- **Direct Scale Access**: `accent1()` through `accent12()`, `gray1()` through `gray12()` -- **No More Variant Duplication**: Removed 30+ variant-specific tokens -- **Single Source of Truth**: All colors come from `FortalThemeColors` scales -- **Matches Fortal Spec**: Uses `{accent}[9]` notation directly in code diff --git a/demo/.gitignore b/demo/.gitignore deleted file mode 100644 index 79c113f9..00000000 --- a/demo/.gitignore +++ /dev/null @@ -1,45 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.build/ -.buildlog/ -.history -.svn/ -.swiftpm/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.pub-cache/ -.pub/ -/build/ - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/demo/.metadata b/demo/.metadata deleted file mode 100644 index de745e4a..00000000 --- a/demo/.metadata +++ /dev/null @@ -1,45 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled. - -version: - revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - channel: stable - -project_type: app - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - - platform: android - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - - platform: ios - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - - platform: linux - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - - platform: macos - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - - platform: web - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - - platform: windows - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/demo/PREVIEW.md b/demo/PREVIEW.md deleted file mode 100644 index 4c19baa7..00000000 --- a/demo/PREVIEW.md +++ /dev/null @@ -1,188 +0,0 @@ -# Remix Widget Preview 🎨 - -Flutter Widget Preview integration for Remix components, providing an interactive browser-based preview environment for rapid development and testing. - -## Prerequisites - -- **Flutter 3.36.0+** (beta channel recommended) -- **Chrome browser** (required for widget preview) -- Widget preview is an experimental feature - APIs may change - -## Quick Start - -### Option 1: Use the Script (Recommended) -```bash -cd demo -./scripts/preview.sh -``` - -### Option 2: Direct Command -```bash -cd demo -flutter widget-preview start -``` - -### Option 3: Clean and Start -```bash -cd demo -flutter widget-preview clean -flutter widget-preview start -``` - -## What's Included - -### πŸ“‹ Form Components -- **Checkbox States**: Unchecked, checked, disabled states -- **Switch States**: On/off states with enabled/disabled variants -- **Radio Group**: Multiple options with selection state -- **Text Fields**: Basic, with icons, password field, disabled state -- **Slider Examples**: Different values and disabled state -- **Select Dropdown**: Dropdown with multiple options - -### πŸŽ›οΈ Layout Components -- **Accordion**: Basic, with icons, pre-expanded, rich content -- **Cards**: Basic card, with actions, profile card, stats dashboard -- **Buttons**: Basic buttons, states, icon-only, variations - -## How It Works - -1. **Start Command**: Launches a local web server -2. **Chrome Opens**: Automatically opens preview environment -3. **Interactive Sidebar**: Lists all `@Preview` annotated functions -4. **Live Updates**: Hot reload when you save changes -5. **Responsive**: Each preview has defined viewport size - -## Preview Structure - -``` -demo/lib/previews/ -β”œβ”€β”€ preview_helper.dart # Shared helper function -β”œβ”€β”€ accordion_preview.dart # Accordion component previews -β”œβ”€β”€ button_preview.dart # Button component previews -β”œβ”€β”€ card_preview.dart # Card component previews -└── form_preview.dart # Form component previews -``` - -## Adding New Previews - -### 1. Create Preview Function -```dart -@Preview(name: 'My Widget Example', size: Size(400, 300)) -Widget previewMyWidget() { - return createRemixPreview( - MyRemixWidget( - // Configure your widget - ), - ); -} -``` - -### 2. Use the Helper -Always use `createRemixPreview()` helper to ensure: -- Proper Remix theming and tokens -- Material design context -- Consistent background and centering -- Debug banner disabled - -### 3. Size Guidelines -- **Forms**: `Size(350-400, 200-400)` depending on content -- **Cards**: `Size(400, 250-400)` for readability -- **Buttons**: `Size(300-400, 150-300)` based on layout -- **Complex Layouts**: `Size(500, 400+)` for more space - -## Technical Details - -### Preview Helper Function -```dart -Widget createRemixPreview(Widget child) { - return createRemixScope( - child: MaterialApp( - debugShowCheckedModeBanner: false, - home: Scaffold( - backgroundColor: Colors.grey[50], - body: Center(child: child), - ), - ), - ); -} -``` - -### Key Features -- **Remix Tokens**: Full access to design system tokens -- **Theme Support**: Automatic light/dark theme handling -- **Hot Reload**: Changes reflect immediately -- **No Interaction**: Uses empty callbacks for preview safety -- **Consistent Styling**: All previews use same wrapper - -## Browser Environment - -### Supported -βœ… Chrome (primary browser) -βœ… Hot reload and live updates -βœ… Responsive viewport controls -βœ… Zoom and inspection tools - -### Not Supported -❌ Native platform APIs -❌ dart:io library -❌ Platform-specific plugins -❌ IDE integration (browser only) - -## Troubleshooting - -### Port Already in Use -If you see port conflicts: -```bash -flutter widget-preview clean -flutter widget-preview start -``` - -### Chrome Not Opening -Manually navigate to: `http://localhost:9000` (or port shown in terminal) - -### Hot Reload Not Working -1. Ensure you're saving files in the preview directory -2. Check terminal for any error messages -3. Try refreshing the browser page - -### Widget Not Appearing -1. Verify `@Preview` annotation is properly imported -2. Check that function returns a Widget -3. Ensure all required parameters are constant/public - -## Performance Tips - -- Keep preview functions lightweight -- Use `const` constructors where possible -- Avoid expensive computations in previews -- Limit preview count per file for faster loading - -## Contributing - -When adding new component previews: - -1. **Follow naming convention**: `preview[ComponentName][Variant]()` -2. **Add descriptive names**: Clear preview names in annotations -3. **Show multiple states**: Demonstrate different configurations -4. **Use proper sizing**: Choose appropriate viewport dimensions -5. **Test thoroughly**: Verify previews load correctly - -## Useful Commands - -```bash -# Clean preview cache -flutter widget-preview clean - -# Check Flutter version -flutter --version - -# View available Flutter commands -flutter help - -# Check widget preview help -flutter widget-preview --help -``` - ---- - -**Note**: Widget Preview is experimental. Expect changes in future Flutter releases. \ No newline at end of file diff --git a/demo/README.md b/demo/README.md deleted file mode 100644 index dbd403a0..00000000 --- a/demo/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# demo - -A new Flutter project. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/demo/analysis_options.yaml b/demo/analysis_options.yaml deleted file mode 100644 index 0d290213..00000000 --- a/demo/analysis_options.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at https://dart.dev/lints. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/demo/build.yaml b/demo/build.yaml deleted file mode 100644 index 0b6b9947..00000000 --- a/demo/build.yaml +++ /dev/null @@ -1,6 +0,0 @@ -targets: - $default: - builders: - widgetbook_generator:use_case_builder: - options: - nav_path_mode: use-case \ No newline at end of file diff --git a/demo/lib/addons/brightness_addon.dart b/demo/lib/addons/brightness_addon.dart deleted file mode 100644 index 8274f5d0..00000000 --- a/demo/lib/addons/brightness_addon.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:widgetbook/widgetbook.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart'; - -class WidgetBookBrightness { - static const light = 'light'; - static const dark = 'dark'; -} - -class BrightnessAddon extends WidgetbookAddon { - final String initialBrightness; - - BrightnessAddon({ - this.initialBrightness = WidgetBookBrightness.light, - }) : super(name: 'brightness'); - - @override - Widget buildUseCase( - BuildContext context, - Widget child, - String setting, - ) { - return MediaQuery( - data: MediaQueryData( - platformBrightness: setting == WidgetBookBrightness.light - ? Brightness.light - : Brightness.dark, - ), - child: child, - ); - } - - @override - List> get fields { - return [ - ObjectDropdownField( - name: 'brightness', - initialValue: initialBrightness, - values: [ - WidgetBookBrightness.light, - WidgetBookBrightness.dark, - ], - ) - ]; - } - - @override - String valueFromQueryGroup(Map group) { - return valueOf('brightness', group)!; - } -} - -class BrightnessAddonConfig extends AddonConfig { - const BrightnessAddonConfig(String value) - : super( - 'brightness', - 'brightness:$value', - ); -} diff --git a/demo/lib/addons/icon_data_knob.dart b/demo/lib/addons/icon_data_knob.dart deleted file mode 100644 index 26416858..00000000 --- a/demo/lib/addons/icon_data_knob.dart +++ /dev/null @@ -1,65 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:widgetbook/widgetbook.dart'; - -enum IconDataEnum { - none, - home, - settings, - favorite, - add, - delete, -} - -class IconDataKnob extends Knob { - IconDataKnob({ - required super.label, - super.initialValue, - }); - - @override - List get fields => [ - ObjectDropdownField( - name: label, - initialValue: IconDataEnum.none, - labelBuilder: (value) => value.name, - values: IconDataEnum.values, - ), - ]; - - @override - IconData? valueFromQueryGroup(Map group) { - final iconDataString = group[label]; - if (iconDataString != null) { - final iconDataEnum = IconDataEnum.values.firstWhere( - (e) => e.toString() == 'IconDataEnum.$iconDataString', - orElse: () => IconDataEnum.home, - ); - return _iconDataFromEnum(iconDataEnum); - } - return null; - } - - IconData? _iconDataFromEnum(IconDataEnum iconDataEnum) { - return switch (iconDataEnum) { - IconDataEnum.home => Icons.home, - IconDataEnum.settings => Icons.settings, - IconDataEnum.favorite => Icons.favorite, - IconDataEnum.add => Icons.add, - IconDataEnum.delete => Icons.delete, - IconDataEnum.none => null, - }; - } -} - -extension IconDataKnobBuilder on KnobsBuilder { - IconData? iconData({ - required String label, - IconData? initialValue, - }) => - onKnobAdded( - IconDataKnob( - label: label, - initialValue: initialValue, - ), - ); -} diff --git a/demo/lib/api/action/button.dart b/demo/lib/api/action/button.dart deleted file mode 100644 index 835b3ac2..00000000 --- a/demo/lib/api/action/button.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'dart:developer'; - -import 'package:flutter/material.dart' hide ButtonStyle; -import 'package:remix/remix.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - body: Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - spacing: 8, - children: [ - RemixButton( - label: 'Click Me', - onPressed: () { - log('Button pressed!'); - }, - style: RemixButtonStyle() - .color(MixColors.black) - .animate(AnimationConfig.linear(100.ms)) - .onHovered(RemixButtonStyle() - .color(MixColors.greySwatch[800]!)), - ), - RemixIconButton( - icon: Icons.add, - onPressed: () { - log('Button pressed!'); - }, - ), - ], - ), - ), - ), - ); - } -} diff --git a/demo/lib/api/content_presentation/avatar.dart b/demo/lib/api/content_presentation/avatar.dart deleted file mode 100644 index 05efaa52..00000000 --- a/demo/lib/api/content_presentation/avatar.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - body: Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - spacing: 8, - children: [ - const RemixAvatar( - label: 'CA', - backgroundImage: - NetworkImage('https://i.pravatar.cc/150?img=48'), - ), - const RemixAvatar( - label: 'CA', - foregroundImage: - NetworkImage('https://i.pravatar.cc/150?img=48'), - ), - const RemixAvatar( - foregroundImage: - NetworkImage('https://i.pravatar.cc/150?img=48'), - child: Icon(Icons.person), - ), - RemixAvatar( - backgroundImage: - const NetworkImage('https://i.pravatar.cc/150?img=48'), - style: RemixAvatarStyle().iconColor(MixColors.white), - child: const Icon(Icons.person), - ), - ], - ), - ), - ), - ); - } -} diff --git a/demo/lib/api/content_presentation/card.dart b/demo/lib/api/content_presentation/card.dart deleted file mode 100644 index 3fd11f19..00000000 --- a/demo/lib/api/content_presentation/card.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: Scaffold( - backgroundColor: MixColors.white, - body: Center( - child: SizedBox( - width: 300, - child: RemixCard( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Card Title', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 8), - Text( - 'This is an example of a card component using RemixCard.', - style: TextStyle(fontSize: 14), - ), - ], - ), - ), - ), - ), - ), - ); - } -} diff --git a/demo/lib/api/feedback/callout.dart b/demo/lib/api/feedback/callout.dart deleted file mode 100644 index 9131fc4e..00000000 --- a/demo/lib/api/feedback/callout.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - body: Center( - child: RemixCallout( - text: 'Hello, world!', - icon: Icons.info, - ), - ), - ), - ); - } -} diff --git a/demo/lib/api/feedback/progress.dart b/demo/lib/api/feedback/progress.dart deleted file mode 100644 index fd9e1c53..00000000 --- a/demo/lib/api/feedback/progress.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: Scaffold( - body: Center( - child: SizedBox( - width: 200, - child: RemixProgress( - value: 0.3, - ), - ), - ), - ), - ); - } -} diff --git a/demo/lib/api/feedback/spinner.dart b/demo/lib/api/feedback/spinner.dart deleted file mode 100644 index 833b454e..00000000 --- a/demo/lib/api/feedback/spinner.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: Scaffold( - body: Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - spacing: 16, - children: [ - RemixSpinner(), - RemixSpinner( - // Note: Style system differs in new implementation - ), - ], - ), - ), - ), - ); - } -} diff --git a/demo/lib/api/form/checkbox.dart b/demo/lib/api/form/checkbox.dart deleted file mode 100644 index 7a86304f..00000000 --- a/demo/lib/api/form/checkbox.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatefulWidget { - const MyApp({super.key}); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - bool _value = false; - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - body: Center( - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - RemixCheckbox( - selected: _value, - style: RemixCheckboxStyle() - .color(MixColors.blue) - .onHovered( - RemixCheckboxStyle().color(MixColors.blue[700]!), - ), - semanticLabel: 'Checkbox', - onChanged: (value) { - setState(() { - _value = value ?? false; - }); - }, - ), - const SizedBox(width: 8), - const Text('Checkbox'), - ], - ), - ), - ), - ); - } -} diff --git a/demo/lib/api/form/radio.dart b/demo/lib/api/form/radio.dart deleted file mode 100644 index c7b92bf2..00000000 --- a/demo/lib/api/form/radio.dart +++ /dev/null @@ -1,72 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatefulWidget { - const MyApp({super.key}); - - @override - State createState() => _MyAppState(); -} - -enum Options { - banana, - apple, - orange, -} - -class _MyAppState extends State { - Options? _value; - - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - body: Center( - child: RemixRadioGroup( - groupValue: _value, - onChanged: (value) { - setState(() { - _value = value; - }); - }, - child: const Column( - spacing: 8, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _LabeledRadio(option: Options.banana, label: 'Banana'), - _LabeledRadio(option: Options.apple, label: 'Apple'), - _LabeledRadio(option: Options.orange, label: 'Orange'), - ], - ), - ), - ), - ), - ); - } -} - -class _LabeledRadio extends StatelessWidget { - const _LabeledRadio({required this.option, required this.label}); - - final Options option; - final String label; - - @override - Widget build(BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - RemixRadio( - value: option, - ), - const SizedBox(width: 8), - Text(label), - ], - ); - } -} diff --git a/demo/lib/api/form/select.dart b/demo/lib/api/form/select.dart deleted file mode 100644 index 8231549f..00000000 --- a/demo/lib/api/form/select.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:demo/helpers/string.dart'; -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -void main() { - runApp(const MyApp()); -} - -enum Options { - banana, - apple, - orange, -} - -class MyApp extends StatefulWidget { - const MyApp({super.key}); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - Options? _value; - - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - backgroundColor: MixColors.white, - body: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text('Select Demo - Simplified for Migration'), - const SizedBox(height: 20), - // Simple select implementation for demo purposes - RemixSelect( - trigger: const RemixSelectTrigger( - placeholder: 'Select an item', - ), - selectedValue: _value, - onChanged: (value) { - setState(() { - _value = value; - }); - }, - items: Options.values - .map((e) => - RemixSelectItem(value: e, label: e.name.capitalize())) - .toList(), - ), - ], - ), - ), - ), - ); - } -} \ No newline at end of file diff --git a/demo/lib/api/form/slider.dart b/demo/lib/api/form/slider.dart deleted file mode 100644 index 53c76420..00000000 --- a/demo/lib/api/form/slider.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatefulWidget { - const MyApp({super.key}); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - double _value = 0.5; - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - body: Center( - child: SizedBox( - width: 200, - child: RemixSlider( - value: _value, - style: RemixSliderStyle(), - onChanged: (value) { - setState(() { - _value = value; - }); - }, - ), - ), - ), - ), - ); - } -} diff --git a/demo/lib/api/form/switch.dart b/demo/lib/api/form/switch.dart deleted file mode 100644 index 8d4a3ea0..00000000 --- a/demo/lib/api/form/switch.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatefulWidget { - const MyApp({super.key}); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - bool _value = false; - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - body: Center( - child: RemixSwitch( - selected: _value, - onChanged: (value) { - setState(() { - _value = value; - }); - }, - ), - ), - ), - ); - } -} diff --git a/demo/lib/api/form/textfield.dart b/demo/lib/api/form/textfield.dart deleted file mode 100644 index 5bedc804..00000000 --- a/demo/lib/api/form/textfield.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: NewWidget(), - ); - } -} - -class NewWidget extends StatefulWidget { - const NewWidget({ - super.key, - }); - - @override - State createState() => _NewWidgetState(); -} - -class _NewWidgetState extends State { - final controller = TextEditingController(); - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: MixColors.white, - body: Center( - child: RemixTextField( - hintText: 'Enter username here', - helperText: 'This is your public display name.', - controller: controller, - style: RemixTextFieldStyle().width(300), - ), - ), - ); - } -} diff --git a/demo/lib/api/layout/divider.dart b/demo/lib/api/layout/divider.dart deleted file mode 100644 index dd14f9a7..00000000 --- a/demo/lib/api/layout/divider.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: Scaffold( - body: Center( - child: RemixDivider(), - ), - ), - ); - } -} diff --git a/demo/lib/api/overlay/tooltip.dart b/demo/lib/api/overlay/tooltip.dart deleted file mode 100644 index 3658c37c..00000000 --- a/demo/lib/api/overlay/tooltip.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: Scaffold( - body: Center( - child: Row( - children: [ - RemixTooltip( - tooltipChild: Text( - 'This is a tooltip', - style: TextStyle(color: MixColors.white), - ), - child: Text('Hello'), - ), - Tooltip( - message: 'This is a tooltip', - child: Text('Hello Mate'), - ), - ], - ), - ), - ), - ); - } -} diff --git a/demo/lib/api/utility/badge.dart b/demo/lib/api/utility/badge.dart deleted file mode 100644 index 7484d5f1..00000000 --- a/demo/lib/api/utility/badge.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: Scaffold( - backgroundColor: MixColors.white, - body: Center( - child: Column( - spacing: 16, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - RemixBadge( - label: 'New', - ), - RemixBadge( - label: 'person', - ), - ], - ), - ), - ), - ); - } -} diff --git a/demo/lib/blocks/auth.dart b/demo/lib/blocks/auth.dart deleted file mode 100644 index 731b21f0..00000000 --- a/demo/lib/blocks/auth.dart +++ /dev/null @@ -1,154 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:mix/mix.dart'; -import 'package:remix/remix.dart' as remix; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: AuthBlock(), - ); - } -} - -class AuthBlock extends StatefulWidget { - const AuthBlock({super.key}); - - @override - State createState() => _AuthBlockState(); -} - -class _AuthBlockState extends State { - bool showPassword = false; - final usernameController = TextEditingController(); - final passwordController = TextEditingController(); - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: MixColors.white, - body: SafeArea( - minimum: const EdgeInsets.all(20), - child: Column( - mainAxisSize: MainAxisSize.min, - spacing: 24, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 8, - children: [ - const Text( - 'Sign in', - style: TextStyle(fontSize: 32, fontWeight: FontWeight.w500), - ), - Row( - spacing: 8, - children: [ - const Text( - 'Don\'t have an account?', - style: TextStyle(fontSize: 15), - ), - remix.RemixButton( - onPressed: () {}, - label: 'Create account', - // style: LinkButtonStyle(), - ), - ], - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 16, - children: [ - FlexBox( - style: $flexbox - ..direction(Axis.vertical) - ..border.all.color.grey(300) - ..clipBehavior(Clip.antiAlias) - ..color.grey(300) - ..borderRadius.circular(8), - children: [ - remix.RemixTextField( - controller: usernameController, - hintText: 'Username', - // style: TextFieldStyle(), - ), - remix.RemixTextField( - controller: passwordController, - obscureText: !showPassword, - hintText: 'Password', - trailing: remix.RemixButton( - onPressed: () { - setState(() { - showPassword = !showPassword; - }); - }, - label: showPassword ? 'Hide' : 'Show', - ), - // style: TextFieldStyle(), - ), - ], - ), - remix.RemixButton( - label: 'Forgot password?', - onPressed: () {}, - // style: LinkButtonStyle(), - ), - remix.RemixButton( - onPressed: () {}, - label: 'Sign in', - // Custom style needed - using defaults for now - ), - ], - ), - Row( - spacing: 8, - children: [ - const Expanded(child: remix.RemixDivider()), - StyledText( - 'or', - style: $text..color.grey(500), - ), - const Expanded(child: remix.RemixDivider()), - ], - ), - Column( - spacing: 8, - children: [ - remix.RemixButton( - label: 'Continue with Apple', - onPressed: () {}, - icon: Icons.apple, - // style: SocialMediaButtonStyle(), - ), - remix.RemixButton( - label: 'Continue with Facebook', - onPressed: () {}, - icon: Icons.facebook, - // style: SocialMediaButtonStyle(), - ), - remix.RemixButton( - label: 'Show more options', - onPressed: () {}, - icon: Icons.add, - // style: SocialMediaButtonStyle(), - ), - ], - ), - ], - ), - ), - ); - } -} - -// Custom styles are now applied inline in the components above -// This follows the Mix 2.0 pattern where styles can be composed directly -// using the style builders and Mix utilities within each component diff --git a/demo/lib/components/avatar_use_case.dart b/demo/lib/components/avatar_use_case.dart deleted file mode 100644 index 40fe5f09..00000000 --- a/demo/lib/components/avatar_use_case.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook/widgetbook.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -final _key = GlobalKey(); - -@widgetbook.UseCase( - name: 'Avatar Component', - type: RemixAvatar, -) -Widget buildAvatarUseCase(BuildContext context) { - final imageUrl = context.knobs.string( - label: 'Image URL', - initialValue: 'https://i.pravatar.cc/150?img=48', - ); - - return KeyedSubtree( - key: _key, - child: Scaffold( - body: Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - RemixAvatar( - foregroundImage: - imageUrl.isNotEmpty ? NetworkImage(imageUrl) : null, - label: 'CA', - ), - ], - ), - ), - ), - ); -} diff --git a/demo/lib/components/badge_use_case.dart b/demo/lib/components/badge_use_case.dart deleted file mode 100644 index 7795a7b7..00000000 --- a/demo/lib/components/badge_use_case.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:flutter/material.dart' hide Badge; -import 'package:remix/remix.dart'; -import 'package:widgetbook/widgetbook.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -@widgetbook.UseCase( - name: 'Badge Component', - type: RemixBadge, -) -Widget buildAvatarUseCase(BuildContext context) { - return Scaffold( - body: Center( - child: RemixBadge( - label: context.knobs.string( - label: 'Label', - initialValue: 'New', - ), - ), - ), - ); -} diff --git a/demo/lib/components/button_real_world_examples.dart b/demo/lib/components/button_real_world_examples.dart deleted file mode 100644 index 125f9940..00000000 --- a/demo/lib/components/button_real_world_examples.dart +++ /dev/null @@ -1,611 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -@widgetbook.UseCase( - name: 'Real World Examples', - type: RemixButton, -) -Widget buildButtonRealWorldExamples(BuildContext context) { - return Scaffold( - body: Padding( - padding: const EdgeInsets.all(16.0), - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Real World Button Usage Examples', - style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 16), - - // Form Integration - _buildSection( - 'Form Integration', - [ - _FormExample(), - ], - ), - - // Loading States - _buildSection( - 'Async Operations & Loading States', - [ - _LoadingStatesExample(), - ], - ), - - // Confirmation Flows - _buildSection( - 'Confirmation & Destructive Actions', - [ - _ConfirmationFlowExample(), - ], - ), - - // Navigation & Actions - _buildSection( - 'Navigation & Action Patterns', - [ - _NavigationExample(), - ], - ), - - // Accessibility Demo - _buildSection( - 'Accessibility & Keyboard Navigation', - [ - _AccessibilityExample(), - ], - ), - ], - ), - ), - ), - ); -} - -Widget _buildSection(String title, List children) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600), - ), - const SizedBox(height: 12), - ...children, - const SizedBox(height: 24), - ], - ); -} - -class _FormExample extends StatefulWidget { - @override - State<_FormExample> createState() => _FormExampleState(); -} - -class _FormExampleState extends State<_FormExample> { - final _formKey = GlobalKey(); - final _emailController = TextEditingController(); - final _passwordController = TextEditingController(); - bool _isSubmitting = false; - bool _agreedToTerms = false; - - @override - void dispose() { - _emailController.dispose(); - _passwordController.dispose(); - super.dispose(); - } - - bool get _isFormValid => - _emailController.text.isNotEmpty && - _passwordController.text.isNotEmpty && - _agreedToTerms; - - Future _submitForm() async { - if (!_formKey.currentState!.validate()) return; - - setState(() => _isSubmitting = true); - - // Simulate API call - await Future.delayed(const Duration(seconds: 2)); - - setState(() => _isSubmitting = false); - - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Form submitted successfully!')), - ); - } - } - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - ), - child: Form( - key: _formKey, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Registration Form Example', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), - ), - const SizedBox(height: 16), - TextFormField( - controller: _emailController, - decoration: const InputDecoration( - labelText: 'Email', - border: OutlineInputBorder(), - ), - validator: (value) => - value?.isEmpty == true ? 'Email is required' : null, - onChanged: (_) => setState(() {}), - ), - const SizedBox(height: 12), - TextFormField( - controller: _passwordController, - obscureText: true, - decoration: const InputDecoration( - labelText: 'Password', - border: OutlineInputBorder(), - ), - validator: (value) => - value?.isEmpty == true ? 'Password is required' : null, - onChanged: (_) => setState(() {}), - ), - const SizedBox(height: 12), - CheckboxListTile( - value: _agreedToTerms, - onChanged: (value) => - setState(() => _agreedToTerms = value ?? false), - title: const Text('I agree to the Terms and Conditions'), - controlAffinity: ListTileControlAffinity.leading, - contentPadding: EdgeInsets.zero, - ), - const SizedBox(height: 16), - Row( - children: [ - RemixButton( - label: _isSubmitting ? 'Submitting...' : 'Submit', - icon: _isSubmitting ? Icons.hourglass_empty : Icons.send, - style: FortalButtonStyle.solid(), - loading: _isSubmitting, - enabled: _isFormValid && !_isSubmitting, - onPressed: _submitForm, - ), - const SizedBox(width: 12), - RemixButton( - label: 'Reset', - icon: Icons.refresh, - style: FortalButtonStyle.solid(), - enabled: !_isSubmitting, - onPressed: () { - _formKey.currentState?.reset(); - _emailController.clear(); - _passwordController.clear(); - setState(() => _agreedToTerms = false); - }, - ), - ], - ), - ], - ), - ), - ); - } -} - -class _LoadingStatesExample extends StatefulWidget { - @override - State<_LoadingStatesExample> createState() => _LoadingStatesExampleState(); -} - -class _LoadingStatesExampleState extends State<_LoadingStatesExample> { - bool _downloadLoading = false; - bool _uploadLoading = false; - bool _syncLoading = false; - - Future _simulateOperation( - String operation, Function(bool) setLoading) async { - setLoading(true); - await Future.delayed(const Duration(seconds: 3)); - setLoading(false); - - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('$operation completed!')), - ); - } - } - - @override - Widget build(BuildContext context) { - return Wrap( - spacing: 12, - runSpacing: 12, - children: [ - RemixButton( - label: _downloadLoading ? 'Downloading...' : 'Download', - icon: _downloadLoading ? Icons.download : Icons.download_rounded, - style: FortalButtonStyle.solid(), - loading: _downloadLoading, - onPressed: _downloadLoading - ? null - : () => _simulateOperation( - 'Download', - (loading) => setState(() => _downloadLoading = loading), - ), - ), - RemixButton( - label: _uploadLoading ? 'Uploading...' : 'Upload', - icon: _uploadLoading ? Icons.upload : Icons.upload_rounded, - style: FortalButtonStyle.solid(), - loading: _uploadLoading, - onPressed: _uploadLoading - ? null - : () => _simulateOperation( - 'Upload', - (loading) => setState(() => _uploadLoading = loading), - ), - ), - RemixButton( - label: _syncLoading ? 'Syncing...' : 'Sync', - icon: _syncLoading ? Icons.sync : Icons.sync_rounded, - style: FortalButtonStyle.solid(), - loading: _syncLoading, - onPressed: _syncLoading - ? null - : () => _simulateOperation( - 'Sync', - (loading) => setState(() => _syncLoading = loading), - ), - ), - ], - ); - } -} - -class _ConfirmationFlowExample extends StatefulWidget { - @override - State<_ConfirmationFlowExample> createState() => - _ConfirmationFlowExampleState(); -} - -class _ConfirmationFlowExampleState extends State<_ConfirmationFlowExample> { - bool _showDeleteConfirmation = false; - bool _isDeleting = false; - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (!_showDeleteConfirmation) ...[ - Wrap( - spacing: 12, - runSpacing: 12, - children: [ - RemixButton( - label: 'Save Changes', - icon: Icons.save, - style: FortalButtonStyle.solid(), - onPressed: () { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Changes saved!')), - ); - }, - ), - RemixButton( - label: 'Delete Item', - icon: Icons.delete, - style: FortalButtonStyle.solid(), - onPressed: () => setState(() => _showDeleteConfirmation = true), - ), - RemixButton( - label: 'Archive', - icon: Icons.archive, - style: FortalButtonStyle.solid(), - onPressed: () { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Item archived!')), - ); - }, - ), - ], - ), - ] else ...[ - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: MixColors.red[50]!, - border: Border.all(color: MixColors.red[200]!), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.warning, color: MixColors.red[700]!, size: 20), - const SizedBox(width: 8), - Text( - 'Confirm Deletion', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: MixColors.red[700]!, - ), - ), - ], - ), - const SizedBox(height: 12), - const Text( - 'Are you sure you want to delete this item? This action cannot be undone.'), - const SizedBox(height: 16), - Row( - children: [ - RemixButton( - label: _isDeleting ? 'Deleting...' : 'Yes, Delete', - icon: _isDeleting - ? Icons.hourglass_empty - : Icons.delete_forever, - style: FortalButtonStyle.solid(), - loading: _isDeleting, - onPressed: _isDeleting - ? null - : () async { - final messenger = ScaffoldMessenger.of(context); - setState(() => _isDeleting = true); - await Future.delayed(const Duration(seconds: 2)); - if (mounted) { - setState(() { - _isDeleting = false; - _showDeleteConfirmation = false; - }); - messenger.showSnackBar( - const SnackBar( - content: Text('Item deleted!')), - ); - } - }, - ), - const SizedBox(width: 12), - RemixButton( - label: 'Cancel', - icon: Icons.cancel, - style: FortalButtonStyle.solid(), - enabled: !_isDeleting, - onPressed: () => - setState(() => _showDeleteConfirmation = false), - ), - ], - ), - ], - ), - ), - ], - ], - ); - } -} - -class _NavigationExample extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Wrap( - spacing: 12, - runSpacing: 12, - children: [ - RemixButton( - label: 'Go Back', - icon: Icons.arrow_back, - style: FortalButtonStyle.solid(), - onPressed: () { - final navigator = Navigator.of(context); - final messenger = ScaffoldMessenger.of(context); - if (navigator.canPop()) { - navigator.pop(); - } else { - messenger.showSnackBar( - const SnackBar(content: Text('No previous page to go back to')), - ); - } - }, - ), - RemixButton( - label: 'Next Step', - icon: Icons.arrow_forward, - style: FortalButtonStyle.solid(), - onPressed: () { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Moving to next step...')), - ); - }, - ), - RemixButton( - label: 'Open Menu', - icon: Icons.menu, - style: FortalButtonStyle.solid(), - onPressed: () { - Scaffold.of(context).openDrawer(); - }, - ), - RemixButton( - label: 'Show More Options', - icon: Icons.more_vert, - style: FortalButtonStyle.solid(), - onPressed: () { - showModalBottomSheet( - context: context, - builder: (context) => Container( - padding: const EdgeInsets.all(16), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - leading: const Icon(Icons.share), - title: const Text('Share'), - onTap: () => Navigator.pop(context), - ), - ListTile( - leading: const Icon(Icons.copy), - title: const Text('Copy Link'), - onTap: () => Navigator.pop(context), - ), - ListTile( - leading: const Icon(Icons.report), - title: const Text('Report'), - onTap: () => Navigator.pop(context), - ), - ], - ), - ), - ); - }, - ), - ], - ); - } -} - -class _AccessibilityExample extends StatefulWidget { - @override - State<_AccessibilityExample> createState() => _AccessibilityExampleState(); -} - -class _AccessibilityExampleState extends State<_AccessibilityExample> { - final int _focusedButtonIndex = -1; - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: MixColors.blue[50]!, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: MixColors.blue[200]!), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.accessibility, - color: MixColors.blue[700]!, size: 16), - const SizedBox(width: 8), - Text( - 'Accessibility Features:', - style: TextStyle( - fontWeight: FontWeight.w600, - color: MixColors.blue[700]!, - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - 'β€’ Tab navigation between buttons\n' - 'β€’ Space/Enter key activation\n' - 'β€’ Screen reader support with semantic labels\n' - 'β€’ Focus indicators\n' - 'β€’ Proper button roles and states', - style: TextStyle( - fontSize: 12, - color: MixColors.blue[800]!, - ), - ), - ], - ), - ), - const SizedBox(height: 16), - const Text( - 'Try navigating with Tab key and activating with Space/Enter:', - style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500), - ), - const SizedBox(height: 12), - Wrap( - spacing: 12, - runSpacing: 12, - children: [ - RemixButton( - label: 'First Button', - icon: Icons.looks_one, - style: FortalButtonStyle.solid(), - semanticLabel: 'First button for accessibility demo', - semanticHint: 'Activate to perform first action', - autofocus: true, - onPressed: () { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('First button activated!')), - ); - }, - ), - RemixButton( - label: 'Second Button', - icon: Icons.looks_two, - style: FortalButtonStyle.solid(), - semanticLabel: 'Second button for accessibility demo', - semanticHint: 'Activate to perform second action', - onPressed: () { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Second button activated!')), - ); - }, - ), - RemixButton( - label: 'Third Button', - icon: Icons.looks_3, - style: FortalButtonStyle.solid(), - semanticLabel: 'Third button for accessibility demo', - semanticHint: 'Activate to perform third action', - onPressed: () { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Third button activated!')), - ); - }, - ), - RemixButton( - label: 'Disabled Button', - icon: Icons.block, - style: FortalButtonStyle.solid(), - enabled: false, - semanticLabel: 'Disabled button example', - semanticHint: 'This button is disabled and cannot be activated', - onPressed: () {}, - ), - ], - ), - const SizedBox(height: 12), - if (_focusedButtonIndex >= 0) - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: MixColors.green[50]!, - borderRadius: BorderRadius.circular(4), - border: Border.all(color: MixColors.green[300]!), - ), - child: Text( - 'Currently focused: Button ${_focusedButtonIndex + 1}', - style: TextStyle( - fontSize: 12, - color: MixColors.green[700]!, - fontWeight: FontWeight.w500, - ), - ), - ), - ], - ); - } -} diff --git a/demo/lib/components/button_showcase.dart b/demo/lib/components/button_showcase.dart deleted file mode 100644 index 8fedb5b8..00000000 --- a/demo/lib/components/button_showcase.dart +++ /dev/null @@ -1,430 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -@widgetbook.UseCase( - name: 'Button Showcase', - type: RemixButton, -) -Widget buildButtonShowcase(BuildContext context) { - return Scaffold( - body: Padding( - padding: const EdgeInsets.all(16.0), - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Button Variants', - style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 16), - - // Base style demonstration - _buildSection( - 'Base Style', - [ - _buildButtonRow('Default Button', FortalButtonStyle.solid()), - ], - ), - - // Sizes section - _buildSection( - 'Sizes', - [ - _buildSizeRow(), - ], - ), - - // States section - _buildSection( - 'States', - [ - _buildStatesRow(), - ], - ), - - // Interactive State Demo - _buildSection( - 'Interactive State Demonstration', - [ - _buildInteractiveStateDemo(), - ], - ), - - // State Callbacks Demo - _buildSection( - 'State Callbacks & Events', - [ - _buildStateCallbacksDemo(), - ], - ), - ], - ), - ), - ), - ); -} - -Widget _buildSection(String title, List children) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600), - ), - const SizedBox(height: 12), - ...children, - const SizedBox(height: 24), - ], - ); -} - -Widget _buildButtonRow(String variantName, RemixButtonStyle style) { - return Padding( - padding: const EdgeInsets.only(bottom: 12.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - variantName, - style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), - ), - const SizedBox(height: 8), - Wrap( - spacing: 8, - runSpacing: 8, - children: [ - RemixButton( - label: 'Default', - icon: Icons.star, - onPressed: () => debugPrint('$variantName default pressed'), - style: style, - ), - RemixButton( - label: 'Icon Only', - icon: Icons.star, - onPressed: () => debugPrint('$variantName icon pressed'), - style: style, - ), - RemixButton( - label: 'Text Only', - onPressed: () => debugPrint('$variantName text pressed'), - style: style, - ), - ], - ), - ], - ), - ); -} - -Widget _buildSizeRow() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Using custom sizes with padding and fontSize', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - const SizedBox(height: 8), - Wrap( - spacing: 12, - runSpacing: 12, - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - RemixButton( - label: 'Small', - icon: Icons.circle, - onPressed: () => debugPrint('Small button pressed'), - style: FortalButtonStyle.solid().paddingAll(8.0), - ), - RemixButton( - label: 'Medium', - icon: Icons.circle, - onPressed: () => debugPrint('Medium button pressed'), - style: FortalButtonStyle.solid().paddingAll(12.0), - ), - RemixButton( - label: 'Large', - icon: Icons.circle, - onPressed: () => debugPrint('Large button pressed'), - style: FortalButtonStyle.solid().paddingAll(16.0), - ), - ], - ), - ], - ); -} - -Widget _buildStatesRow() { - return Wrap( - spacing: 12, - runSpacing: 12, - children: [ - RemixButton( - label: 'Enabled', - icon: Icons.check, - onPressed: () => debugPrint('Enabled button pressed'), - style: FortalButtonStyle.solid(), - ), - RemixButton( - label: 'Disabled', - icon: Icons.block, - enabled: false, - onPressed: () => debugPrint('This should not print'), - style: FortalButtonStyle.solid(), - ), - RemixButton( - label: 'Loading', - icon: Icons.refresh, - loading: true, - onPressed: () => debugPrint('Loading button pressed'), - style: FortalButtonStyle.solid(), - ), - ], - ); -} - -class _StateTracker extends StatefulWidget { - final Widget child; - final String label; - - const _StateTracker({required this.child, required this.label}); - - @override - State<_StateTracker> createState() => _StateTrackerState(); -} - -class _StateTrackerState extends State<_StateTracker> { - final bool _isHovered = false; - final bool _isPressed = false; - final bool _isFocused = false; - final int _pressCount = 0; - final int _longPressCount = 0; - final int _doubleTapCount = 0; - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.label, - style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), - ), - const SizedBox(height: 8), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - widget.child, - const SizedBox(width: 16), - Expanded( - child: Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: MixColors.grey[100], - borderRadius: BorderRadius.circular(8), - border: Border.all(color: MixColors.grey[300]!), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Current States:', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: MixColors.grey[700], - ), - ), - const SizedBox(height: 4), - Wrap( - spacing: 4, - runSpacing: 4, - children: [ - _buildStateChip('Hovered', _isHovered, MixColors.blue), - _buildStateChip('Pressed', _isPressed, MixColors.red), - _buildStateChip('Focused', _isFocused, MixColors.green), - ], - ), - const SizedBox(height: 8), - Text( - 'Event Counters:', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: MixColors.grey[700], - ), - ), - const SizedBox(height: 4), - Text( - 'Press: $_pressCount | Long Press: $_longPressCount | Double Tap: $_doubleTapCount', - style: - TextStyle(fontSize: 10, color: MixColors.grey[600]), - ), - ], - ), - ), - ), - ], - ), - ], - ); - } - - Widget _buildStateChip(String label, bool isActive, Color color) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: isActive ? color.withValues(alpha: 0.2) : MixColors.transparent, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: isActive ? color : MixColors.grey[400]!, - width: 1, - ), - ), - child: Text( - label, - style: TextStyle( - fontSize: 10, - fontWeight: isActive ? FontWeight.w600 : FontWeight.normal, - color: isActive ? color : MixColors.grey[600], - ), - ), - ); - } -} - -Widget _buildInteractiveStateDemo() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Hover, click, and use keyboard navigation to see state changes in real-time:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - const SizedBox(height: 16), - _StateTracker( - label: 'Primary Button with State Tracking', - child: RemixButton( - label: 'Interactive Demo', - icon: Icons.touch_app, - style: FortalButtonStyle.solid(), - onPressed: () => debugPrint('Primary button pressed'), - onLongPress: () => debugPrint('Primary button long pressed'), - onDoubleTap: () => debugPrint('Primary button double tapped'), - ), - ), - const SizedBox(height: 16), - _StateTracker( - label: 'Outline Button with State Tracking', - child: RemixButton( - label: 'Hover & Click Me', - icon: Icons.mouse, - style: FortalButtonStyle.solid(), - onPressed: () => debugPrint('Outline button pressed'), - onLongPress: () => debugPrint('Outline button long pressed'), - onDoubleTap: () => debugPrint('Outline button double tapped'), - ), - ), - const SizedBox(height: 16), - _StateTracker( - label: 'Ghost Button with State Tracking', - child: RemixButton( - label: 'Focus & Press Me', - icon: Icons.keyboard, - style: FortalButtonStyle.solid(), - onPressed: () => debugPrint('Ghost button pressed'), - onLongPress: () => debugPrint('Ghost button long pressed'), - onDoubleTap: () => debugPrint('Ghost button double tapped'), - ), - ), - ], - ); -} - -Widget _buildStateCallbacksDemo() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Comprehensive event handling demonstration:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - const SizedBox(height: 16), - Wrap( - spacing: 12, - runSpacing: 12, - children: [ - RemixButton( - label: 'Press Events', - icon: Icons.tap_and_play, - style: FortalButtonStyle.solid(), - onPressed: () => debugPrint('βœ… Single Press'), - onLongPress: () => debugPrint('⏳ Long Press (Hold for 500ms)'), - onDoubleTap: () => debugPrint('⚑ Double Tap'), - ), - RemixButton( - label: 'Hover Events', - icon: Icons.mouse, - style: FortalButtonStyle.solid(), - onPressed: () => debugPrint('Button clicked'), - ), - RemixButton( - label: 'Focus Events', - icon: Icons.keyboard, - style: FortalButtonStyle.solid(), - onPressed: () => debugPrint('Focused button clicked'), - ), - RemixButton( - label: 'All State Changes', - icon: Icons.analytics, - style: FortalButtonStyle.solid(), - onPressed: () => debugPrint('State tracking button clicked'), - ), - ], - ), - const SizedBox(height: 16), - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: MixColors.amber[50], - borderRadius: BorderRadius.circular(8), - border: Border.all(color: MixColors.amber[200]!), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.info, size: 16, color: MixColors.amber[700]), - const SizedBox(width: 8), - Text( - 'Event Testing Tips:', - style: TextStyle( - fontWeight: FontWeight.w600, - color: MixColors.amber[700], - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - 'β€’ Use Tab key for keyboard navigation and focus events\n' - 'β€’ Hold buttons for 500ms+ to trigger long press\n' - 'β€’ Double-tap quickly for double-tap events\n' - 'β€’ Hover with mouse to see hover state changes\n' - 'β€’ Check debug console for detailed event logs', - style: TextStyle( - fontSize: 12, - color: MixColors.amber[800], - ), - ), - ], - ), - ), - ], - ); -} diff --git a/demo/lib/components/button_use_case.dart b/demo/lib/components/button_use_case.dart deleted file mode 100644 index 2dd89411..00000000 --- a/demo/lib/components/button_use_case.dart +++ /dev/null @@ -1,64 +0,0 @@ -import 'package:demo/addons/icon_data_knob.dart'; -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook/widgetbook.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -final _key = GlobalKey(); - -@widgetbook.UseCase( - name: 'Button Component', - type: RemixButton, -) -Widget buildButtonUseCase(BuildContext context) { - return KeyedSubtree( - key: _key, - child: Scaffold( - body: Center( - child: Builder(builder: (context) { - // Use default Fortal solid variant layered over base metrics - RemixButtonStyle buttonStyle = FortalButtonStyle.solid(); - - return RemixButton( - onPressed: () { - debugPrint('βœ… RemixButton pressed'); - }, - onLongPress: context.knobs.boolean( - label: 'Enable Long Press', - initialValue: true, - ) - ? () { - debugPrint('⏳ RemixButton long pressed'); - } - : null, - onDoubleTap: context.knobs.boolean( - label: 'Enable Double Tap', - initialValue: true, - ) - ? () { - debugPrint('⚑ RemixButton double tapped'); - } - : null, - enabled: context.knobs.boolean( - label: 'Enabled', - initialValue: true, - ), - loading: context.knobs.boolean( - label: 'Loading', - initialValue: false, - ), - label: context.knobs.string( - label: 'label', - initialValue: 'Interactive Button', - ), - icon: context.knobs.iconData( - label: 'Icon', - initialValue: Icons.touch_app, - ), - style: buttonStyle, - ); - }), - ), - ), - ); -} diff --git a/demo/lib/components/callout_use_case.dart b/demo/lib/components/callout_use_case.dart deleted file mode 100644 index 38161ebc..00000000 --- a/demo/lib/components/callout_use_case.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart' as m; -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -final _key = GlobalKey(); - -@widgetbook.UseCase( - name: 'Callout Component', - type: RemixCallout, -) -Widget buildCalloutUseCase(BuildContext context) { - return KeyedSubtree( - key: _key, - child: Scaffold( - body: Center( - child: SizedBox( - width: 300, - child: RemixCallout( - icon: m.Icons.info_outline, - text: 'Lucas', - ), - ), - ), - ), - ); -} diff --git a/demo/lib/components/card_use_case.dart b/demo/lib/components/card_use_case.dart deleted file mode 100644 index b3044c19..00000000 --- a/demo/lib/components/card_use_case.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -@widgetbook.UseCase( - name: 'Card Component', - type: RemixCard, -) -Widget buildCard(BuildContext context) { - return Scaffold( - body: Center( - child: RemixCard( - child: RowBox( - style: $flexbox - ..spacing(12) - ..mainAxisSize(MainAxisSize.min), - children: [ - const RemixAvatar(label: 'LF'), - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - StyledText( - 'Leo Farias', - style: $text - ..style.fontSize(14) - ..style.fontWeight(FontWeight.bold) - ..style.color.black87(), - ), - StyledText( - 'Flutter Engineer', - style: $text - ..style.fontSize(12) - ..style.color.black54(), - ), - ], - ), - ], - ), - ), - ), - ); -} diff --git a/demo/lib/components/checkbox_showcase.dart b/demo/lib/components/checkbox_showcase.dart deleted file mode 100644 index 6896f79d..00000000 --- a/demo/lib/components/checkbox_showcase.dart +++ /dev/null @@ -1,867 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -@widgetbook.UseCase( - name: 'Checkbox Showcase', - type: RemixCheckbox, -) -Widget buildCheckboxShowcase(BuildContext context) { - return Scaffold( - body: Padding( - padding: const EdgeInsets.all(16.0), - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Checkbox Variants', - style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 16), - - // Basic states demonstration - _buildSection( - 'Basic States', - [ - _buildBasicStatesDemo(), - ], - ), - - // Tristate demonstration - _buildSection( - 'Tristate (Indeterminate)', - [ - _buildTristateDemo(), - ], - ), - - // States section - _buildSection( - 'Interactive States', - [ - _buildInteractiveStatesDemo(), - ], - ), - - // With Labels section - _buildSection( - 'With Labels & Layouts', - [ - _buildLabelLayoutsDemo(), - ], - ), - - // Event Handling Demo - _buildSection( - 'Event Handling & State Tracking', - [ - _buildEventHandlingDemo(), - ], - ), - - // Real-world Examples - _buildSection( - 'Real-World Examples', - [ - _buildRealWorldExamples(), - ], - ), - ], - ), - ), - ), - ); -} - -Widget _buildSection(String title, List children) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600), - ), - const SizedBox(height: 12), - ...children, - const SizedBox(height: 24), - ], - ); -} - -Widget _buildBasicStatesDemo() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Basic checkbox states with different selections:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - const SizedBox(height: 16), - Wrap( - spacing: 24, - runSpacing: 16, - children: [ - _buildLabeledCheckbox('Unchecked', false, enabled: true), - _buildLabeledCheckbox('Checked', true, enabled: true), - _buildLabeledCheckbox('Disabled Unchecked', false, enabled: false), - _buildLabeledCheckbox('Disabled Checked', true, enabled: false), - ], - ), - ], - ); -} - -Widget _buildTristateDemo() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Tristate checkboxes can be true, false, or null (indeterminate):', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - const SizedBox(height: 16), - _TristateDemo(), - ], - ); -} - -class _TristateDemo extends StatefulWidget { - @override - State<_TristateDemo> createState() => _TristateState(); -} - -class _TristateState extends State<_TristateDemo> { - bool? _parentValue; - bool _child1 = false; - bool _child2 = false; - bool _child3 = false; - - void _updateParent() { - final checkedCount = [_child1, _child2, _child3].where((v) => v).length; - setState(() { - if (checkedCount == 0) { - _parentValue = false; - } else if (checkedCount == 3) { - _parentValue = true; - } else { - _parentValue = null; // Indeterminate - } - }); - } - - void _updateChildren(bool? value) { - setState(() { - _parentValue = value; - if (value != null) { - _child1 = _child2 = _child3 = value; - } - }); - } - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Parent checkbox - Row( - children: [ - RemixCheckbox( - selected: _parentValue, - tristate: true, - onChanged: _updateChildren, - semanticLabel: 'Select All', - ), - const SizedBox(width: 8), - const Text('Select All', style: TextStyle(fontWeight: FontWeight.w600)), - ], - ), - const SizedBox(height: 8), - - // Child checkboxes - Padding( - padding: const EdgeInsets.only(left: 24), - child: Column( - children: [ - Row( - children: [ - RemixCheckbox( - selected: _child1, - onChanged: (value) { - setState(() => _child1 = value ?? false); - _updateParent(); - }, - semanticLabel: 'Option 1', - ), - const SizedBox(width: 8), - const Text('Option 1'), - ], - ), - const SizedBox(height: 8), - Row( - children: [ - RemixCheckbox( - selected: _child2, - onChanged: (value) { - setState(() => _child2 = value ?? false); - _updateParent(); - }, - semanticLabel: 'Option 2', - ), - const SizedBox(width: 8), - const Text('Option 2'), - ], - ), - const SizedBox(height: 8), - Row( - children: [ - RemixCheckbox( - selected: _child3, - onChanged: (value) { - setState(() => _child3 = value ?? false); - _updateParent(); - }, - semanticLabel: 'Option 3', - ), - const SizedBox(width: 8), - const Text('Option 3'), - ], - ), - ], - ), - ), - const SizedBox(height: 16), - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: MixColors.blue[50], - borderRadius: BorderRadius.circular(8), - border: Border.all(color: MixColors.blue[200]!), - ), - child: Text( - 'Parent state: ${_parentValue == null ? 'Indeterminate' : _parentValue! ? 'All selected' : 'None selected'}', - style: TextStyle( - fontSize: 12, - color: MixColors.blue[700], - fontWeight: FontWeight.w500, - ), - ), - ), - ], - ); - } -} - -Widget _buildInteractiveStatesDemo() { - return const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Interactive states with visual feedback:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - SizedBox(height: 16), - Wrap( - spacing: 24, - runSpacing: 16, - children: [ - _StateTrackingCheckbox(label: 'Hover & Click Me'), - _StateTrackingCheckbox(label: 'Focus with Tab', autoFocus: true), - ], - ), - ], - ); -} - -class _StateTrackingCheckbox extends StatefulWidget { - final String label; - final bool autoFocus; - - const _StateTrackingCheckbox({ - required this.label, - this.autoFocus = false, - }); - - @override - State<_StateTrackingCheckbox> createState() => _StateTrackingCheckboxState(); -} - -class _StateTrackingCheckboxState extends State<_StateTrackingCheckbox> { - bool _selected = false; - int _changeCount = 0; - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - RemixCheckbox( - selected: _selected, - autofocus: widget.autoFocus, - onChanged: (value) { - setState(() { - _selected = value ?? false; - _changeCount++; - }); - debugPrint('${widget.label}: ${value == true ? 'checked' : 'unchecked'} (count: $_changeCount)'); - }, - semanticLabel: widget.label, - ), - const SizedBox(width: 8), - Text(widget.label), - ], - ), - const SizedBox(height: 4), - Text( - 'State: ${_selected ? 'Checked' : 'Unchecked'} | Changes: $_changeCount', - style: TextStyle( - fontSize: 10, - color: MixColors.grey[600], - ), - ), - ], - ); - } -} - -Widget _buildLabelLayoutsDemo() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Different label layouts and arrangements:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - const SizedBox(height: 16), - - // Left label - Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Text('Left Label'), - const SizedBox(width: 8), - _buildSimpleCheckbox(true), - ], - ), - const SizedBox(height: 12), - - // Right label - Row( - mainAxisSize: MainAxisSize.min, - children: [ - _buildSimpleCheckbox(false), - const SizedBox(width: 8), - const Text('Right Label'), - ], - ), - const SizedBox(height: 12), - - // Vertical layout - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - const Text('Top Label'), - const SizedBox(height: 4), - _buildSimpleCheckbox(true), - ], - ), - const SizedBox(height: 12), - - // In a list tile style - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - _buildSimpleCheckbox(false), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'List Item Style', - style: TextStyle(fontWeight: FontWeight.w500), - ), - Text( - 'With description text below the main label', - style: TextStyle( - fontSize: 12, - color: MixColors.grey[600], - ), - ), - ], - ), - ), - ], - ), - ), - ], - ); -} - -Widget _buildEventHandlingDemo() { - return _EventHandlingDemo(); -} - -class _EventHandlingDemo extends StatefulWidget { - @override - State<_EventHandlingDemo> createState() => _EventHandlingDemoState(); -} - -class _EventHandlingDemoState extends State<_EventHandlingDemo> { - final List _eventLog = []; - bool _logEnabled = true; - - void _logEvent(String event) { - if (_logEnabled) { - setState(() { - _eventLog.insert(0, '${DateTime.now().toIso8601String().split('T')[1].split('.')[0]}: $event'); - if (_eventLog.length > 5) { - _eventLog.removeLast(); - } - }); - } - } - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Event callbacks and logging demonstration:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - const SizedBox(height: 16), - - Row( - children: [ - _buildSimpleCheckbox(_logEnabled, onChanged: (value) { - setState(() => _logEnabled = value ?? false); - if (!_logEnabled) { - _eventLog.clear(); - } - }), - const SizedBox(width: 8), - const Text('Enable Event Logging'), - ], - ), - const SizedBox(height: 16), - - // Demo checkboxes - Wrap( - spacing: 24, - children: [ - _EventCheckbox(label: 'Checkbox A', onEvent: _logEvent), - _EventCheckbox(label: 'Checkbox B', onEvent: _logEvent), - _EventCheckbox(label: 'Checkbox C', onEvent: _logEvent), - ], - ), - - const SizedBox(height: 16), - - // Event log display - Container( - width: double.infinity, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: MixColors.grey[900], - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Event Log:', - style: TextStyle( - color: MixColors.grey[300], - fontWeight: FontWeight.w600, - fontSize: 12, - ), - ), - const SizedBox(height: 8), - ..._eventLog.map((event) => Text( - event, - style: TextStyle( - color: MixColors.green[400], - fontFamily: 'Courier', - fontSize: 11, - ), - )), - if (_eventLog.isEmpty) - Text( - _logEnabled ? 'No events yet...' : 'Event logging disabled', - style: TextStyle( - color: MixColors.grey[500], - fontStyle: FontStyle.italic, - fontSize: 11, - ), - ), - ], - ), - ), - ], - ); - } -} - -class _EventCheckbox extends StatefulWidget { - final String label; - final Function(String) onEvent; - - const _EventCheckbox({required this.label, required this.onEvent}); - - @override - State<_EventCheckbox> createState() => _EventCheckboxState(); -} - -class _EventCheckboxState extends State<_EventCheckbox> { - bool _selected = false; - - @override - Widget build(BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - RemixCheckbox( - selected: _selected, - onChanged: (value) { - setState(() => _selected = value ?? false); - widget.onEvent('${widget.label}: ${value == true ? 'Checked' : 'Unchecked'}'); - }, - semanticLabel: widget.label, - ), - const SizedBox(width: 8), - Text(widget.label), - ], - ); - } -} - -Widget _buildRealWorldExamples() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Real-world usage examples:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - const SizedBox(height: 16), - - // Terms and conditions - _TermsExample(), - const SizedBox(height: 24), - - // Feature selection - _FeatureSelectionExample(), - const SizedBox(height: 24), - - // Task checklist - _TaskChecklistExample(), - ], - ); -} - -class _TermsExample extends StatefulWidget { - @override - State<_TermsExample> createState() => _TermsExampleState(); -} - -class _TermsExampleState extends State<_TermsExample> { - bool _acceptedTerms = false; - bool _acceptedPrivacy = false; - bool _acceptedMarketing = false; - - bool get canProceed => _acceptedTerms && _acceptedPrivacy; - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Account Registration', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), - ), - const SizedBox(height: 16), - - // Required agreements - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RemixCheckbox( - selected: _acceptedTerms, - onChanged: (value) => setState(() => _acceptedTerms = value ?? false), - semanticLabel: 'Accept Terms of Service', - ), - const SizedBox(width: 8), - const Expanded( - child: Text('I accept the Terms of Service *'), - ), - ], - ), - const SizedBox(height: 12), - - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RemixCheckbox( - selected: _acceptedPrivacy, - onChanged: (value) => setState(() => _acceptedPrivacy = value ?? false), - semanticLabel: 'Accept Privacy Policy', - ), - const SizedBox(width: 8), - const Expanded( - child: Text('I accept the Privacy Policy *'), - ), - ], - ), - const SizedBox(height: 12), - - // Optional agreement - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RemixCheckbox( - selected: _acceptedMarketing, - onChanged: (value) => setState(() => _acceptedMarketing = value ?? false), - semanticLabel: 'Receive marketing emails', - ), - const SizedBox(width: 8), - const Expanded( - child: Text('I would like to receive marketing emails (optional)'), - ), - ], - ), - - const SizedBox(height: 16), - - // Submit button - SizedBox( - width: double.infinity, - child: RemixButton( - label: 'Create Account', - onPressed: canProceed ? () => debugPrint('Account created!') : null, - style: FortalButtonStyle.solid(), - ), - ), - ], - ), - ); - } -} - -class _FeatureSelectionExample extends StatefulWidget { - @override - State<_FeatureSelectionExample> createState() => _FeatureSelectionExampleState(); -} - -class _FeatureSelectionExampleState extends State<_FeatureSelectionExample> { - final Map _features = { - 'Dark Mode': true, - 'Push Notifications': false, - 'Auto-save': true, - 'Analytics': false, - 'Cloud Sync': true, - 'Offline Mode': false, - }; - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Feature Selection', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), - ), - const SizedBox(height: 8), - Text( - 'Choose which features you want to enable:', - style: TextStyle(color: MixColors.grey[600]), - ), - const SizedBox(height: 16), - - ..._features.entries.map((entry) => Padding( - padding: const EdgeInsets.only(bottom: 12), - child: Row( - children: [ - RemixCheckbox( - selected: entry.value, - onChanged: (value) { - setState(() => _features[entry.key] = value ?? false); - }, - semanticLabel: entry.key, - ), - const SizedBox(width: 8), - Text(entry.key), - ], - ), - )), - - const SizedBox(height: 8), - Text( - 'Selected: ${_features.values.where((v) => v).length} of ${_features.length} features', - style: TextStyle( - fontSize: 12, - color: MixColors.grey[600], - fontStyle: FontStyle.italic, - ), - ), - ], - ), - ); - } -} - -class _TaskChecklistExample extends StatefulWidget { - @override - State<_TaskChecklistExample> createState() => _TaskChecklistExampleState(); -} - -class _TaskChecklistExampleState extends State<_TaskChecklistExample> { - final List> _tasks = [ - {'title': 'Set up development environment', 'completed': true}, - {'title': 'Create project structure', 'completed': true}, - {'title': 'Implement user authentication', 'completed': false}, - {'title': 'Design database schema', 'completed': false}, - {'title': 'Write API endpoints', 'completed': false}, - {'title': 'Create unit tests', 'completed': false}, - ]; - - @override - Widget build(BuildContext context) { - final completedCount = _tasks.where((task) => task['completed']).length; - final progress = completedCount / _tasks.length; - - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Project Checklist', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), - ), - Text( - '$completedCount/${_tasks.length} completed', - style: TextStyle( - color: MixColors.grey[600], - fontWeight: FontWeight.w500, - ), - ), - ], - ), - const SizedBox(height: 8), - - // Progress bar - Container( - height: 8, - decoration: BoxDecoration( - color: MixColors.grey[200], - borderRadius: BorderRadius.circular(4), - ), - child: FractionallySizedBox( - alignment: Alignment.centerLeft, - widthFactor: progress, - child: Container( - decoration: BoxDecoration( - color: progress == 1.0 ? MixColors.green[500] : MixColors.blue[500], - borderRadius: BorderRadius.circular(4), - ), - ), - ), - ), - - const SizedBox(height: 16), - - ..._tasks.asMap().entries.map((entry) { - final index = entry.key; - final task = entry.value; - - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Row( - children: [ - RemixCheckbox( - selected: task['completed'], - onChanged: (value) { - setState(() => _tasks[index]['completed'] = value ?? false); - }, - semanticLabel: task['title'], - ), - const SizedBox(width: 8), - Expanded( - child: Text( - task['title'], - style: TextStyle( - decoration: task['completed'] ? TextDecoration.lineThrough : null, - color: task['completed'] ? MixColors.grey[500] : null, - ), - ), - ), - ], - ), - ); - }), - ], - ), - ); - } -} - -// Helper functions -Widget _buildLabeledCheckbox(String label, bool selected, {bool enabled = true}) { - return Column( - children: [ - RemixCheckbox( - selected: selected, - enabled: enabled, - onChanged: enabled ? (value) => debugPrint('$label: $value') : null, - semanticLabel: label, - ), - const SizedBox(height: 4), - Text( - label, - style: TextStyle( - fontSize: 12, - color: enabled ? null : MixColors.grey[500], - ), - ), - ], - ); -} - -Widget _buildSimpleCheckbox(bool selected, {ValueChanged? onChanged}) { - return RemixCheckbox( - selected: selected, - onChanged: onChanged ?? (value) => debugPrint('Checkbox: $value'), - ); -} \ No newline at end of file diff --git a/demo/lib/components/checkbox_use_case.dart b/demo/lib/components/checkbox_use_case.dart deleted file mode 100644 index 3bbe19ce..00000000 --- a/demo/lib/components/checkbox_use_case.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:demo/helpers/use_case_state.dart'; -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook/widgetbook.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -final _key = GlobalKey(); - -@widgetbook.UseCase( - name: 'Checkbox Component', - type: RemixCheckbox, -) -Widget buildCheckboxUseCase(BuildContext context) { - final knobState = WidgetbookState.of(context); - - return Scaffold( - body: KeyedSubtree( - key: _key, - child: Center( - child: _CheckboxPreview( - label: context.knobs.string(label: 'Label', initialValue: 'Label'), - enabled: context.knobs.boolean(label: 'Enabled', initialValue: true), - selected: context.knobs.boolean(label: 'Checked', initialValue: true), - onChanged: (value) => knobState.updateKnob('Checked', value), - ), - ), - ), - ); -} - -class _CheckboxPreview extends StatelessWidget { - const _CheckboxPreview({ - required this.label, - required this.enabled, - required this.selected, - this.onChanged, - }); - - final String label; - final bool enabled; - final bool selected; - final ValueChanged? onChanged; - - @override - Widget build(BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - RemixCheckbox( - enabled: enabled, - selected: selected, - onChanged: onChanged, - semanticLabel: label, - ), - const SizedBox(width: 8), - Text(label), - ], - ); - } -} diff --git a/demo/lib/components/divider_use_case.dart b/demo/lib/components/divider_use_case.dart deleted file mode 100644 index 1acae437..00000000 --- a/demo/lib/components/divider_use_case.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:remix/remix.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -@widgetbook.UseCase( - name: 'Divider Component', - type: RemixDivider, -) -Widget buildDivider(BuildContext context) { - return const Scaffold( - body: Center( - child: SizedBox( - height: 100, - width: 100, - child: Center( - child: RemixDivider(), - ), - ), - ), - ); -} diff --git a/demo/lib/components/progress_use_case.dart b/demo/lib/components/progress_use_case.dart deleted file mode 100644 index 30b57f18..00000000 --- a/demo/lib/components/progress_use_case.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook/widgetbook.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -@widgetbook.UseCase( - name: 'Progress Component', - type: RemixProgress, -) -Widget buildProgressUseCase(BuildContext context) { - return Scaffold( - body: Center( - child: SizedBox( - width: 200, - child: RemixProgress( - value: context.knobs.double.slider( - label: 'value', - min: 0, - max: 1, - initialValue: 0.5, - ), - ), - ), - ), - ); -} diff --git a/demo/lib/components/radio_showcase.dart b/demo/lib/components/radio_showcase.dart deleted file mode 100644 index 710b5452..00000000 --- a/demo/lib/components/radio_showcase.dart +++ /dev/null @@ -1,1187 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -@widgetbook.UseCase( - name: 'Radio Showcase', - type: RemixRadio, -) -Widget buildRadioShowcase(BuildContext context) { - return Scaffold( - body: Padding( - padding: const EdgeInsets.all(16.0), - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Radio Button Groups', - style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 16), - - // Basic group layouts - _buildSection( - 'Group Layouts', - [ - _buildGroupLayoutsDemo(), - ], - ), - - // States section - _buildSection( - 'States & Behavior', - [ - _buildStatesDemo(), - ], - ), - - // Interactive demonstration - _buildSection( - 'Interactive State Tracking', - [ - _buildInteractiveDemo(), - ], - ), - - // Event handling - _buildSection( - 'Event Handling & Callbacks', - [ - _buildEventHandlingDemo(), - ], - ), - - // Real-world examples - _buildSection( - 'Real-World Examples', - [ - _buildRealWorldExamples(), - ], - ), - ], - ), - ), - ), - ); -} - -Widget _buildSection(String title, List children) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600), - ), - const SizedBox(height: 12), - ...children, - const SizedBox(height: 24), - ], - ); -} - -Widget _buildGroupLayoutsDemo() { - return const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Different layouts for radio button groups:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - SizedBox(height: 16), - - // Vertical layout - _RadioGroupDemo( - title: 'Vertical Layout', - layout: _RadioLayout.vertical, - options: ['Option A', 'Option B', 'Option C'], - initialValue: 'Option A', - ), - - SizedBox(height: 24), - - // Horizontal layout - _RadioGroupDemo( - title: 'Horizontal Layout', - layout: _RadioLayout.horizontal, - options: ['Small', 'Medium', 'Large'], - initialValue: 'Medium', - ), - - SizedBox(height: 24), - - // Grid layout - _RadioGroupDemo( - title: 'Grid Layout (2 columns)', - layout: _RadioLayout.grid, - options: ['Top Left', 'Top Right', 'Bottom Left', 'Bottom Right'], - initialValue: 'Top Left', - ), - ], - ); -} - -enum _RadioLayout { vertical, horizontal, grid } - -class _RadioGroupDemo extends StatefulWidget { - final String title; - final _RadioLayout layout; - final List options; - final String initialValue; - - const _RadioGroupDemo({ - required this.title, - required this.layout, - required this.options, - required this.initialValue, - }); - - @override - State<_RadioGroupDemo> createState() => _RadioGroupDemoState(); -} - -class _RadioGroupDemoState extends State<_RadioGroupDemo> { - late String _selectedValue; - - @override - void initState() { - super.initState(); - _selectedValue = widget.initialValue; - } - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.title, - style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600), - ), - const SizedBox(height: 12), - RemixRadioGroup( - groupValue: _selectedValue, - onChanged: (value) => setState(() => _selectedValue = value!), - child: _buildLayoutWidget(), - ), - const SizedBox(height: 8), - Text( - 'Selected: $_selectedValue', - style: TextStyle( - fontSize: 11, - color: MixColors.grey[600], - fontStyle: FontStyle.italic, - ), - ), - ], - ), - ); - } - - Widget _buildLayoutWidget() { - final radioWidgets = widget.options.map((option) => _buildRadioOption(option)).toList(); - - switch (widget.layout) { - case _RadioLayout.vertical: - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: radioWidgets.map((radio) => Padding( - padding: const EdgeInsets.only(bottom: 8), - child: radio, - )).toList(), - ); - - case _RadioLayout.horizontal: - return Wrap( - spacing: 16, - children: radioWidgets, - ); - - case _RadioLayout.grid: - return Wrap( - spacing: 16, - runSpacing: 8, - children: radioWidgets.map((radio) => SizedBox( - width: 120, - child: radio, - )).toList(), - ); - } - } - - Widget _buildRadioOption(String option) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - RemixRadio(value: option), - const SizedBox(width: 8), - Text(option), - ], - ); - } -} - -Widget _buildStatesDemo() { - return const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Different states and behaviors:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - SizedBox(height: 16), - - // Normal group - _StatesDemoGroup( - title: 'Normal Group', - enabled: true, - toggleable: false, - ), - - SizedBox(height: 20), - - // Disabled group - _StatesDemoGroup( - title: 'Disabled Group', - enabled: false, - toggleable: false, - ), - - SizedBox(height: 20), - - // Toggleable group - _StatesDemoGroup( - title: 'Toggleable Group (can unselect)', - enabled: true, - toggleable: true, - ), - ], - ); -} - -class _StatesDemoGroup extends StatefulWidget { - final String title; - final bool enabled; - final bool toggleable; - - const _StatesDemoGroup({ - required this.title, - required this.enabled, - required this.toggleable, - }); - - @override - State<_StatesDemoGroup> createState() => _StatesDemoGroupState(); -} - -class _StatesDemoGroupState extends State<_StatesDemoGroup> { - String? _selectedValue = 'Option 1'; - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - color: widget.enabled ? null : MixColors.grey[50], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.title, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: widget.enabled ? null : MixColors.grey[500], - ), - ), - const SizedBox(height: 12), - RemixRadioGroup( - groupValue: _selectedValue, - onChanged: (String? value) { - if (widget.enabled) { - setState(() { - // If toggleable and clicking the same value, set to null - if (widget.toggleable && value == _selectedValue) { - _selectedValue = null; - } else { - _selectedValue = value; - } - }); - } - }, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: ['Option 1', 'Option 2', 'Option 3'].map((option) => - Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - RemixRadio( - value: option, - enabled: widget.enabled, - toggleable: widget.toggleable, - ), - const SizedBox(width: 8), - Text( - option, - style: TextStyle( - color: widget.enabled ? null : MixColors.grey[500], - ), - ), - ], - ), - ), - ).toList(), - ), - ), - const SizedBox(height: 8), - Text( - 'Selected: ${_selectedValue ?? 'None'}', - style: TextStyle( - fontSize: 11, - color: MixColors.grey[600], - fontStyle: FontStyle.italic, - ), - ), - ], - ), - ); - } -} - -Widget _buildInteractiveDemo() { - return _InteractiveStateDemo(); -} - -class _InteractiveStateDemo extends StatefulWidget { - @override - State<_InteractiveStateDemo> createState() => _InteractiveStateDemoState(); -} - -class _InteractiveStateDemoState extends State<_InteractiveStateDemo> { - String? _selectedTheme = 'light'; - final List _stateLog = []; - - void _logStateChange(String newValue) { - final timestamp = DateTime.now().toIso8601String().split('T')[1].split('.')[0]; - setState(() { - _stateLog.insert(0, '$timestamp: Changed to $newValue'); - if (_stateLog.length > 4) { - _stateLog.removeLast(); - } - }); - } - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Interactive state tracking with visual feedback:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - const SizedBox(height: 16), - - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Theme Selector with State Tracking', - style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600), - ), - const SizedBox(height: 16), - - RemixRadioGroup( - groupValue: _selectedTheme, - onChanged: (value) { - setState(() => _selectedTheme = value); - if (value != null) { - _logStateChange(value); - } - }, - child: const Column( - children: [ - _InteractiveRadioOption( - value: 'light', - label: 'Light Theme', - description: 'Clean and bright interface', - icon: Icons.light_mode, - ), - SizedBox(height: 12), - _InteractiveRadioOption( - value: 'dark', - label: 'Dark Theme', - description: 'Easy on the eyes in low light', - icon: Icons.dark_mode, - ), - SizedBox(height: 12), - _InteractiveRadioOption( - value: 'system', - label: 'System Theme', - description: 'Follow system preference', - icon: Icons.settings_system_daydream, - ), - ], - ), - ), - - const SizedBox(height: 16), - - // State display - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: MixColors.blue[50], - borderRadius: BorderRadius.circular(6), - border: Border.all(color: MixColors.blue[200]!), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.info, size: 16, color: MixColors.blue[700]), - const SizedBox(width: 8), - Text( - 'Current Selection: ${_selectedTheme ?? 'None'}', - style: TextStyle( - fontWeight: FontWeight.w600, - color: MixColors.blue[700], - fontSize: 12, - ), - ), - ], - ), - if (_stateLog.isNotEmpty) ...[ - const SizedBox(height: 8), - Text( - 'Recent Changes:', - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - color: MixColors.blue[700], - ), - ), - const SizedBox(height: 4), - ..._stateLog.map((log) => Text( - log, - style: TextStyle( - fontSize: 10, - color: MixColors.blue[600], - fontFamily: 'Courier', - ), - )), - ], - ], - ), - ), - ], - ), - ), - ], - ); - } -} - -class _InteractiveRadioOption extends StatelessWidget { - final String value; - final String label; - final String description; - final IconData icon; - - const _InteractiveRadioOption({ - required this.value, - required this.label, - required this.description, - required this.icon, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[200]!), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - RemixRadio(value: value), - const SizedBox(width: 12), - Icon(icon, size: 20, color: MixColors.grey[600]), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - label, - style: const TextStyle( - fontWeight: FontWeight.w500, - fontSize: 14, - ), - ), - Text( - description, - style: TextStyle( - fontSize: 12, - color: MixColors.grey[600], - ), - ), - ], - ), - ), - ], - ), - ); - } -} - -Widget _buildEventHandlingDemo() { - return _EventHandlingDemo(); -} - -class _EventHandlingDemo extends StatefulWidget { - @override - State<_EventHandlingDemo> createState() => _EventHandlingDemoState(); -} - -class _EventHandlingDemoState extends State<_EventHandlingDemo> { - String? _selectedValue; - final List _eventLog = []; - - void _logEvent(String event) { - setState(() { - _eventLog.insert(0, event); - if (_eventLog.length > 6) { - _eventLog.removeLast(); - } - }); - debugPrint(event); - } - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Event callbacks and logging:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - const SizedBox(height: 16), - - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Priority Level Selection', - style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600), - ), - const SizedBox(height: 16), - - RemixRadioGroup( - groupValue: _selectedValue, - onChanged: (value) { - final oldValue = _selectedValue; - setState(() => _selectedValue = value); - - final timestamp = DateTime.now().toIso8601String().split('T')[1].split('.')[0]; - _logEvent('$timestamp: Changed from ${oldValue ?? 'None'} to ${value ?? 'None'}'); - }, - child: const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _EventRadioOption( - value: 'low', - label: 'Low Priority', - color: Colors.green, - ), - SizedBox(height: 8), - _EventRadioOption( - value: 'medium', - label: 'Medium Priority', - color: Colors.yellow, - ), - SizedBox(height: 8), - _EventRadioOption( - value: 'high', - label: 'High Priority', - color: Colors.orange, - ), - SizedBox(height: 8), - _EventRadioOption( - value: 'critical', - label: 'Critical Priority', - color: Colors.red, - ), - ], - ), - ), - - const SizedBox(height: 16), - - // Event console - Container( - width: double.infinity, - height: 120, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: MixColors.grey[900], - borderRadius: BorderRadius.circular(6), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Event Console:', - style: TextStyle( - color: MixColors.grey[300], - fontWeight: FontWeight.w600, - fontSize: 12, - ), - ), - const SizedBox(height: 8), - Expanded( - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: _eventLog.isNotEmpty - ? _eventLog.map((event) => Text( - event, - style: TextStyle( - color: MixColors.green[400], - fontFamily: 'Courier', - fontSize: 11, - ), - )).toList() - : [ - Text( - 'Select options to see events...', - style: TextStyle( - color: MixColors.grey[500], - fontStyle: FontStyle.italic, - fontSize: 11, - ), - ), - ], - ), - ), - ), - ], - ), - ), - ], - ), - ), - ], - ); - } -} - -class _EventRadioOption extends StatelessWidget { - final String value; - final String label; - final Color color; - - const _EventRadioOption({ - required this.value, - required this.label, - required this.color, - }); - - @override - Widget build(BuildContext context) { - return Row( - children: [ - RemixRadio(value: value), - const SizedBox(width: 8), - Container( - width: 12, - height: 12, - decoration: BoxDecoration( - color: color, - borderRadius: BorderRadius.circular(6), - ), - ), - const SizedBox(width: 8), - Text(label), - ], - ); - } -} - -Widget _buildRealWorldExamples() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Real-world usage examples:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - const SizedBox(height: 16), - - // Theme selector - _ThemeSelectionExample(), - const SizedBox(height: 24), - - // Payment method - _PaymentMethodExample(), - const SizedBox(height: 24), - - // Survey/Poll - _SurveyExample(), - ], - ); -} - -class _ThemeSelectionExample extends StatefulWidget { - @override - State<_ThemeSelectionExample> createState() => _ThemeSelectionExampleState(); -} - -class _ThemeSelectionExampleState extends State<_ThemeSelectionExample> { - String _selectedTheme = 'system'; - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Theme Preferences', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), - ), - const SizedBox(height: 8), - Text( - 'Choose your preferred theme:', - style: TextStyle(color: MixColors.grey[600]), - ), - const SizedBox(height: 16), - - RemixRadioGroup( - groupValue: _selectedTheme, - onChanged: (value) => setState(() => _selectedTheme = value!), - child: const Column( - children: [ - _ThemeOption( - value: 'light', - title: 'Light', - description: 'Best for daylight use', - icon: Icons.wb_sunny, - ), - SizedBox(height: 12), - _ThemeOption( - value: 'dark', - title: 'Dark', - description: 'Reduces eye strain in low light', - icon: Icons.nightlight_round, - ), - SizedBox(height: 12), - _ThemeOption( - value: 'system', - title: 'System', - description: 'Automatically match your device', - icon: Icons.phone_android, - ), - ], - ), - ), - - const SizedBox(height: 16), - Container( - width: double.infinity, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: MixColors.blue[50], - borderRadius: BorderRadius.circular(6), - ), - child: Text( - 'Your preference will be saved automatically. Current selection: ${_selectedTheme.toUpperCase()}', - style: TextStyle( - fontSize: 12, - color: MixColors.blue[700], - ), - ), - ), - ], - ), - ); - } -} - -class _ThemeOption extends StatelessWidget { - final String value; - final String title; - final String description; - final IconData icon; - - const _ThemeOption({ - required this.value, - required this.title, - required this.description, - required this.icon, - }); - - @override - Widget build(BuildContext context) { - return Row( - children: [ - RemixRadio(value: value), - const SizedBox(width: 12), - Icon(icon, color: MixColors.grey[600]), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle(fontWeight: FontWeight.w500), - ), - Text( - description, - style: TextStyle( - fontSize: 12, - color: MixColors.grey[600], - ), - ), - ], - ), - ), - ], - ); - } -} - -class _PaymentMethodExample extends StatefulWidget { - @override - State<_PaymentMethodExample> createState() => _PaymentMethodExampleState(); -} - -class _PaymentMethodExampleState extends State<_PaymentMethodExample> { - String? _selectedMethod; - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Payment Method', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), - ), - const SizedBox(height: 8), - Text( - 'Select your payment method:', - style: TextStyle(color: MixColors.grey[600]), - ), - const SizedBox(height: 16), - - RemixRadioGroup( - groupValue: _selectedMethod, - onChanged: (value) => setState(() => _selectedMethod = value), - child: const Column( - children: [ - _PaymentOption( - value: 'credit_card', - title: 'Credit Card', - subtitle: 'Visa, Mastercard, American Express', - icon: Icons.credit_card, - ), - SizedBox(height: 12), - _PaymentOption( - value: 'paypal', - title: 'PayPal', - subtitle: 'Pay with your PayPal account', - icon: Icons.account_balance_wallet, - ), - SizedBox(height: 12), - _PaymentOption( - value: 'apple_pay', - title: 'Apple Pay', - subtitle: 'Pay with Touch ID or Face ID', - icon: Icons.phone_iphone, - ), - SizedBox(height: 12), - _PaymentOption( - value: 'bank_transfer', - title: 'Bank Transfer', - subtitle: 'Direct bank transfer', - icon: Icons.account_balance, - ), - ], - ), - ), - - if (_selectedMethod != null) ...[ - const SizedBox(height: 16), - Container( - width: double.infinity, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: MixColors.green[50], - borderRadius: BorderRadius.circular(6), - border: Border.all(color: MixColors.green[200]!), - ), - child: Row( - children: [ - Icon(Icons.check_circle, color: MixColors.green[600], size: 16), - const SizedBox(width: 8), - Text( - 'Selected: ${_getPaymentMethodName(_selectedMethod!)}', - style: TextStyle( - fontSize: 12, - color: MixColors.green[700], - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ), - ], - ], - ), - ); - } - - String _getPaymentMethodName(String value) { - switch (value) { - case 'credit_card': - return 'Credit Card'; - case 'paypal': - return 'PayPal'; - case 'apple_pay': - return 'Apple Pay'; - case 'bank_transfer': - return 'Bank Transfer'; - default: - return value; - } - } -} - -class _PaymentOption extends StatelessWidget { - final String value; - final String title; - final String subtitle; - final IconData icon; - - const _PaymentOption({ - required this.value, - required this.title, - required this.subtitle, - required this.icon, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[200]!), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - RemixRadio(value: value), - const SizedBox(width: 12), - Icon(icon, color: MixColors.grey[600]), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle(fontWeight: FontWeight.w500), - ), - Text( - subtitle, - style: TextStyle( - fontSize: 12, - color: MixColors.grey[600], - ), - ), - ], - ), - ), - ], - ), - ); - } -} - -class _SurveyExample extends StatefulWidget { - @override - State<_SurveyExample> createState() => _SurveyExampleState(); -} - -class _SurveyExampleState extends State<_SurveyExample> { - String? _satisfaction; - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Customer Satisfaction Survey', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), - ), - const SizedBox(height: 8), - Text( - 'How satisfied are you with our service?', - style: TextStyle(color: MixColors.grey[600]), - ), - const SizedBox(height: 16), - - RemixRadioGroup( - groupValue: _satisfaction, - onChanged: (value) => setState(() => _satisfaction = value), - child: const Column( - children: [ - _SatisfactionOption( - value: 'very_satisfied', - label: 'Very Satisfied', - emoji: 'πŸ˜„', - color: Colors.green, - ), - SizedBox(height: 8), - _SatisfactionOption( - value: 'satisfied', - label: 'Satisfied', - emoji: 'πŸ™‚', - color: Colors.blue, - ), - SizedBox(height: 8), - _SatisfactionOption( - value: 'neutral', - label: 'Neutral', - emoji: '😐', - color: Colors.grey, - ), - SizedBox(height: 8), - _SatisfactionOption( - value: 'dissatisfied', - label: 'Dissatisfied', - emoji: 'πŸ™', - color: Colors.orange, - ), - SizedBox(height: 8), - _SatisfactionOption( - value: 'very_dissatisfied', - label: 'Very Dissatisfied', - emoji: '😞', - color: Colors.red, - ), - ], - ), - ), - - const SizedBox(height: 16), - SizedBox( - width: double.infinity, - child: RemixButton( - label: 'Submit Survey', - onPressed: _satisfaction != null - ? () => debugPrint('Survey submitted: $_satisfaction') - : null, - style: FortalButtonStyle.solid(), - ), - ), - - if (_satisfaction == null) ...[ - const SizedBox(height: 8), - Text( - 'Please select an option to submit', - style: TextStyle( - fontSize: 12, - color: MixColors.red[600], - fontStyle: FontStyle.italic, - ), - ), - ], - ], - ), - ); - } -} - -class _SatisfactionOption extends StatelessWidget { - final String value; - final String label; - final String emoji; - final Color color; - - const _SatisfactionOption({ - required this.value, - required this.label, - required this.emoji, - required this.color, - }); - - @override - Widget build(BuildContext context) { - return Row( - children: [ - RemixRadio(value: value), - const SizedBox(width: 12), - Text(emoji, style: const TextStyle(fontSize: 20)), - const SizedBox(width: 12), - Text(label), - const Spacer(), - Container( - width: 8, - height: 8, - decoration: BoxDecoration( - color: color, - borderRadius: BorderRadius.circular(4), - ), - ), - ], - ); - } -} \ No newline at end of file diff --git a/demo/lib/components/radio_use_case.dart b/demo/lib/components/radio_use_case.dart deleted file mode 100644 index 96ba9b65..00000000 --- a/demo/lib/components/radio_use_case.dart +++ /dev/null @@ -1,70 +0,0 @@ -import 'package:demo/helpers/string.dart'; -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook/widgetbook.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -enum Theme { - dark, - light, - system; -} - -@widgetbook.UseCase( - name: 'Radio Component', - type: RemixRadio, -) -Widget buildRadioUseCase(BuildContext context) { - return Scaffold( - body: Center( - child: ListenableBuilder( - listenable: _state, - builder: (context, child) { - return RemixRadioGroup( - groupValue: _state.value, - onChanged: (value) { - _state.update(value!); - }, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: Theme.values - .map( - (theme) => Padding( - padding: const EdgeInsets.all(4.0), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - RemixRadio( - value: theme, - enabled: context.knobs.boolean( - label: 'Enabled', - initialValue: true, - ), - ), - const SizedBox(width: 8), - Text(theme.name.capitalize()), - ], - ), - ), - ) - .toList(), - ), - ); - }, - ), - ), - ); -} - -class _ThemeState extends ValueNotifier { - _ThemeState(super.value); - - void update(Theme value) { - this.value = value; - notifyListeners(); - } -} - -_ThemeState _state = _ThemeState(Theme.dark); diff --git a/demo/lib/components/select.dart b/demo/lib/components/select.dart deleted file mode 100644 index 85e1f341..00000000 --- a/demo/lib/components/select.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -@widgetbook.UseCase( - name: 'Select Component', - type: RemixSelect, -) -Widget buildSelect(BuildContext context) { - return const Scaffold( - body: Center( - child: SelectDemo(), - ), - ); -} - -class SelectDemo extends StatefulWidget { - const SelectDemo({ - super.key, - }); - - @override - State createState() => _SelectDemoState(); -} - -class _SelectDemoState extends State { - String selectedValue = 'Apple'; - - final List items = ['Apple Fiji', 'Banana', 'Orange']; - - @override - Widget build(BuildContext context) { - return Center( - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - width: 200, - child: RemixSelect( - trigger: const RemixSelectTrigger( - placeholder: 'Select item...', - ), - selectedValue: selectedValue, - onChanged: (value) => - setState(() => selectedValue = value ?? ''), - items: List.generate( - items.length, - (index) => RemixSelectItem( - value: items[index], - label: items[index], - ), - ), - ), - ), - ], - ), - ); - } -} diff --git a/demo/lib/components/slider.dart b/demo/lib/components/slider.dart deleted file mode 100644 index 99d72024..00000000 --- a/demo/lib/components/slider.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:demo/helpers/use_case_state.dart'; -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook/widgetbook.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -final _key = GlobalKey(); - -@widgetbook.UseCase( - name: 'Slider Component', - type: RemixSlider, -) -Widget buildButtonUseCase(BuildContext context) { - final knobState = WidgetbookState.of(context); - return KeyedSubtree( - key: _key, - child: Scaffold( - body: Center( - child: SizedBox( - width: 200, - child: RemixSlider( - onChanged: (value) => knobState.updateKnob('value', value), - enabled: context.knobs.boolean( - label: 'enabled', - initialValue: true, - ), - snapDivisions: context.knobs.int.input( - label: 'snapDivisions', - initialValue: 0, - ), - value: context.knobs.double.slider( - label: 'value', - min: 0, - max: 1, - initialValue: 0.25, - ), - ), - ), - ), - ), - ); -} diff --git a/demo/lib/components/spinner_use_case.dart b/demo/lib/components/spinner_use_case.dart deleted file mode 100644 index 2de89ea8..00000000 --- a/demo/lib/components/spinner_use_case.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -@widgetbook.UseCase( - name: 'Spinner Component', - type: RemixSpinner, -) -Widget buildSpinnerUseCase(BuildContext context) { - return const Scaffold( - body: Center( - child: RemixSpinner(), - ), - ); -} diff --git a/demo/lib/components/switch_showcase.dart b/demo/lib/components/switch_showcase.dart deleted file mode 100644 index e00b2559..00000000 --- a/demo/lib/components/switch_showcase.dart +++ /dev/null @@ -1,942 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -@widgetbook.UseCase( - name: 'Switch Showcase', - type: RemixSwitch, -) -Widget buildSwitchShowcase(BuildContext context) { - return Scaffold( - body: Padding( - padding: const EdgeInsets.all(16.0), - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Switch Components', - style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 16), - - // Basic states demonstration - _buildSection( - 'Basic States', - [ - _buildBasicStatesDemo(), - ], - ), - - // Interactive states section - _buildSection( - 'Interactive States', - [ - _buildInteractiveStatesDemo(), - ], - ), - - // With Labels section - _buildSection( - 'With Labels & Layouts', - [ - _buildLabelLayoutsDemo(), - ], - ), - - // Event handling & tracking - _buildSection( - 'Event Handling & State Tracking', - [ - _buildEventHandlingDemo(), - ], - ), - - // Real-world examples - _buildSection( - 'Real-World Examples', - [ - _buildRealWorldExamples(), - ], - ), - ], - ), - ), - ), - ); -} - -Widget _buildSection(String title, List children) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600), - ), - const SizedBox(height: 12), - ...children, - const SizedBox(height: 24), - ], - ); -} - -Widget _buildBasicStatesDemo() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Basic switch states and behaviors:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - const SizedBox(height: 16), - Wrap( - spacing: 24, - runSpacing: 16, - children: [ - _buildLabeledSwitch('Off', false, enabled: true), - _buildLabeledSwitch('On', true, enabled: true), - _buildLabeledSwitch('Disabled Off', false, enabled: false), - _buildLabeledSwitch('Disabled On', true, enabled: false), - ], - ), - ], - ); -} - -Widget _buildInteractiveStatesDemo() { - return const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Interactive switches with state tracking:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - SizedBox(height: 16), - Wrap( - spacing: 24, - runSpacing: 20, - children: [ - _StateTrackingSwitch(label: 'Click & Hover Me'), - _StateTrackingSwitch(label: 'Focus with Tab', autoFocus: true), - ], - ), - ], - ); -} - -class _StateTrackingSwitch extends StatefulWidget { - final String label; - final bool autoFocus; - - const _StateTrackingSwitch({ - required this.label, - this.autoFocus = false, - }); - - @override - State<_StateTrackingSwitch> createState() => _StateTrackingSwitchState(); -} - -class _StateTrackingSwitchState extends State<_StateTrackingSwitch> { - bool _selected = false; - int _toggleCount = 0; - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - RemixSwitch( - selected: _selected, - autofocus: widget.autoFocus, - onChanged: (value) { - setState(() { - _selected = value; - _toggleCount++; - }); - debugPrint('${widget.label}: ${value ? 'ON' : 'OFF'} (toggles: $_toggleCount)'); - }, - semanticLabel: widget.label, - ), - const SizedBox(width: 12), - Text(widget.label), - ], - ), - const SizedBox(height: 4), - Text( - 'State: ${_selected ? 'ON' : 'OFF'} | Toggles: $_toggleCount', - style: TextStyle( - fontSize: 10, - color: MixColors.grey[600], - ), - ), - ], - ); - } -} - -Widget _buildLabelLayoutsDemo() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Different label layouts and arrangements:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - const SizedBox(height: 16), - - // Left label - Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Text('Left Label'), - const SizedBox(width: 12), - _buildSimpleSwitch(true), - ], - ), - const SizedBox(height: 12), - - // Right label - Row( - mainAxisSize: MainAxisSize.min, - children: [ - _buildSimpleSwitch(false), - const SizedBox(width: 12), - const Text('Right Label'), - ], - ), - const SizedBox(height: 12), - - // Vertical layout - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - const Text('Top Label'), - const SizedBox(height: 8), - _buildSimpleSwitch(true), - ], - ), - const SizedBox(height: 16), - - // Card style layout - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Card Style Toggle', - style: TextStyle(fontWeight: FontWeight.w500), - ), - Text( - 'With detailed description underneath', - style: TextStyle( - fontSize: 12, - color: MixColors.grey[600], - ), - ), - ], - ), - ), - _buildSimpleSwitch(false), - ], - ), - ), - ], - ); -} - -Widget _buildEventHandlingDemo() { - return _EventHandlingDemo(); -} - -class _EventHandlingDemo extends StatefulWidget { - @override - State<_EventHandlingDemo> createState() => _EventHandlingDemoState(); -} - -class _EventHandlingDemoState extends State<_EventHandlingDemo> { - final List _eventLog = []; - bool _logEnabled = true; - - void _logEvent(String event) { - if (_logEnabled) { - setState(() { - _eventLog.insert(0, '${DateTime.now().toIso8601String().split('T')[1].split('.')[0]}: $event'); - if (_eventLog.length > 5) { - _eventLog.removeLast(); - } - }); - } - } - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Event callbacks and logging demonstration:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - const SizedBox(height: 16), - - // Enable/disable logging - Row( - children: [ - RemixSwitch( - selected: _logEnabled, - onChanged: (value) { - setState(() { - _logEnabled = value; - if (!_logEnabled) { - _eventLog.clear(); - } - }); - }, - semanticLabel: 'Enable Event Logging', - ), - const SizedBox(width: 12), - const Text('Enable Event Logging'), - ], - ), - - const SizedBox(height: 16), - - // Demo switches - Wrap( - spacing: 24, - runSpacing: 12, - children: [ - _EventSwitch(label: 'Feature A', onEvent: _logEvent), - _EventSwitch(label: 'Feature B', onEvent: _logEvent), - _EventSwitch(label: 'Feature C', onEvent: _logEvent), - ], - ), - - const SizedBox(height: 16), - - // Event log display - Container( - width: double.infinity, - height: 140, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: MixColors.grey[900], - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Event Log:', - style: TextStyle( - color: MixColors.grey[300], - fontWeight: FontWeight.w600, - fontSize: 12, - ), - ), - const SizedBox(height: 8), - Expanded( - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: _eventLog.isNotEmpty - ? _eventLog.map((event) => Text( - event, - style: TextStyle( - color: MixColors.green[400], - fontFamily: 'Courier', - fontSize: 11, - ), - )).toList() - : [ - Text( - _logEnabled ? 'No events yet...' : 'Event logging disabled', - style: TextStyle( - color: MixColors.grey[500], - fontStyle: FontStyle.italic, - fontSize: 11, - ), - ), - ], - ), - ), - ), - ], - ), - ), - ], - ); - } -} - -class _EventSwitch extends StatefulWidget { - final String label; - final Function(String) onEvent; - - const _EventSwitch({required this.label, required this.onEvent}); - - @override - State<_EventSwitch> createState() => _EventSwitchState(); -} - -class _EventSwitchState extends State<_EventSwitch> { - bool _selected = false; - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - RemixSwitch( - selected: _selected, - onChanged: (value) { - setState(() => _selected = value); - widget.onEvent('${widget.label}: ${value ? 'ON' : 'OFF'}'); - }, - semanticLabel: widget.label, - ), - const SizedBox(width: 8), - Text(widget.label), - ], - ), - const SizedBox(height: 4), - Text( - _selected ? 'Enabled' : 'Disabled', - style: TextStyle( - fontSize: 10, - color: _selected ? MixColors.green[600] : MixColors.grey[500], - fontWeight: FontWeight.w500, - ), - ), - ], - ); - } -} - -Widget _buildRealWorldExamples() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Real-world usage examples:', - style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic), - ), - const SizedBox(height: 16), - - // Settings panel - _SettingsPanelExample(), - const SizedBox(height: 24), - - // Feature flags dashboard - _FeatureFlagsExample(), - const SizedBox(height: 24), - - // Privacy settings - _PrivacySettingsExample(), - ], - ); -} - -class _SettingsPanelExample extends StatefulWidget { - @override - State<_SettingsPanelExample> createState() => _SettingsPanelExampleState(); -} - -class _SettingsPanelExampleState extends State<_SettingsPanelExample> { - bool _darkMode = false; - bool _notifications = true; - bool _soundEffects = true; - bool _analytics = false; - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'App Settings', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), - ), - const SizedBox(height: 8), - Text( - 'Customize your app experience:', - style: TextStyle(color: MixColors.grey[600]), - ), - const SizedBox(height: 16), - - _SettingItem( - icon: Icons.dark_mode, - title: 'Dark Mode', - description: 'Switch to dark theme', - value: _darkMode, - onChanged: (value) => setState(() => _darkMode = value), - ), - - _SettingItem( - icon: Icons.notifications, - title: 'Push Notifications', - description: 'Receive app notifications', - value: _notifications, - onChanged: (value) => setState(() => _notifications = value), - ), - - _SettingItem( - icon: Icons.volume_up, - title: 'Sound Effects', - description: 'Play sounds for interactions', - value: _soundEffects, - onChanged: (value) => setState(() => _soundEffects = value), - ), - - _SettingItem( - icon: Icons.analytics, - title: 'Analytics', - description: 'Help improve the app', - value: _analytics, - onChanged: (value) => setState(() => _analytics = value), - ), - ], - ), - ); - } -} - -class _SettingItem extends StatelessWidget { - final IconData icon; - final String title; - final String description; - final bool value; - final ValueChanged onChanged; - - const _SettingItem({ - required this.icon, - required this.title, - required this.description, - required this.value, - required this.onChanged, - }); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Row( - children: [ - Icon(icon, color: MixColors.grey[600], size: 20), - const SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle(fontWeight: FontWeight.w500), - ), - Text( - description, - style: TextStyle( - fontSize: 12, - color: MixColors.grey[600], - ), - ), - ], - ), - ), - RemixSwitch( - selected: value, - onChanged: onChanged, - semanticLabel: title, - ), - ], - ), - ); - } -} - -class _FeatureFlagsExample extends StatefulWidget { - @override - State<_FeatureFlagsExample> createState() => _FeatureFlagsExampleState(); -} - -class _FeatureFlagsExampleState extends State<_FeatureFlagsExample> { - final Map _features = { - 'experimental_ui': false, - 'beta_search': true, - 'new_dashboard': false, - 'advanced_filters': true, - 'dark_mode_v2': false, - }; - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.flag, color: MixColors.blue[600]), - const SizedBox(width: 8), - const Text( - 'Feature Flags Dashboard', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), - ), - ], - ), - const SizedBox(height: 8), - Text( - 'Enable or disable experimental features:', - style: TextStyle(color: MixColors.grey[600]), - ), - const SizedBox(height: 16), - - ..._features.entries.map((entry) => _FeatureFlagItem( - key: ValueKey(entry.key), - flagKey: entry.key, - value: entry.value, - onChanged: (value) { - setState(() => _features[entry.key] = value); - debugPrint('Feature ${entry.key}: ${value ? 'ENABLED' : 'DISABLED'}'); - }, - )), - - const SizedBox(height: 12), - Container( - width: double.infinity, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: MixColors.amber[50], - borderRadius: BorderRadius.circular(6), - border: Border.all(color: MixColors.amber[200]!), - ), - child: Row( - children: [ - Icon(Icons.warning_amber, size: 16, color: MixColors.amber[700]), - const SizedBox(width: 8), - Expanded( - child: Text( - 'Changes take effect after app restart', - style: TextStyle( - fontSize: 12, - color: MixColors.amber[800], - ), - ), - ), - ], - ), - ), - ], - ), - ); - } -} - -class _FeatureFlagItem extends StatelessWidget { - final String flagKey; - final bool value; - final ValueChanged onChanged; - - const _FeatureFlagItem({ - super.key, - required this.flagKey, - required this.value, - required this.onChanged, - }); - - String get _displayName { - return flagKey - .split('_') - .map((word) => word[0].toUpperCase() + word.substring(1)) - .join(' '); - } - - String get _description { - switch (flagKey) { - case 'experimental_ui': - return 'New experimental user interface'; - case 'beta_search': - return 'Improved search functionality (beta)'; - case 'new_dashboard': - return 'Redesigned dashboard layout'; - case 'advanced_filters': - return 'Advanced filtering options'; - case 'dark_mode_v2': - return 'Next generation dark mode'; - default: - return 'Feature flag: $flagKey'; - } - } - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 6), - child: Row( - children: [ - Container( - width: 8, - height: 8, - decoration: BoxDecoration( - color: value ? MixColors.green[500] : MixColors.grey[400], - borderRadius: BorderRadius.circular(4), - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - _displayName, - style: const TextStyle(fontWeight: FontWeight.w500), - ), - Text( - _description, - style: TextStyle( - fontSize: 12, - color: MixColors.grey[600], - ), - ), - ], - ), - ), - RemixSwitch( - selected: value, - onChanged: onChanged, - semanticLabel: _displayName, - ), - ], - ), - ); - } -} - -class _PrivacySettingsExample extends StatefulWidget { - @override - State<_PrivacySettingsExample> createState() => _PrivacySettingsExampleState(); -} - -class _PrivacySettingsExampleState extends State<_PrivacySettingsExample> { - bool _shareUsageData = false; - bool _personalizedAds = false; - bool _locationServices = true; - bool _crashReporting = true; - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: MixColors.grey[300]!), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.privacy_tip, color: MixColors.blue[600]), - const SizedBox(width: 8), - const Text( - 'Privacy Settings', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), - ), - ], - ), - const SizedBox(height: 8), - Text( - 'Control how your data is used:', - style: TextStyle(color: MixColors.grey[600]), - ), - const SizedBox(height: 16), - - _PrivacyItem( - title: 'Share Usage Data', - description: 'Help improve the app by sharing anonymous usage data', - value: _shareUsageData, - onChanged: (value) => setState(() => _shareUsageData = value), - isRecommended: false, - ), - - _PrivacyItem( - title: 'Personalized Ads', - description: 'Show ads based on your interests and activity', - value: _personalizedAds, - onChanged: (value) => setState(() => _personalizedAds = value), - isRecommended: false, - ), - - _PrivacyItem( - title: 'Location Services', - description: 'Allow location-based features and recommendations', - value: _locationServices, - onChanged: (value) => setState(() => _locationServices = value), - isRecommended: true, - ), - - _PrivacyItem( - title: 'Crash Reporting', - description: 'Automatically send crash reports to help fix bugs', - value: _crashReporting, - onChanged: (value) => setState(() => _crashReporting = value), - isRecommended: true, - ), - - const SizedBox(height: 16), - Container( - width: double.infinity, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: MixColors.blue[50], - borderRadius: BorderRadius.circular(6), - ), - child: Text( - 'Your privacy choices are saved automatically and can be changed at any time.', - style: TextStyle( - fontSize: 12, - color: MixColors.blue[700], - ), - ), - ), - ], - ), - ); - } -} - -class _PrivacyItem extends StatelessWidget { - final String title; - final String description; - final bool value; - final ValueChanged onChanged; - final bool isRecommended; - - const _PrivacyItem({ - required this.title, - required this.description, - required this.value, - required this.onChanged, - required this.isRecommended, - }); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Text( - title, - style: const TextStyle(fontWeight: FontWeight.w500), - ), - if (isRecommended) ...[ - const SizedBox(width: 8), - Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: MixColors.green[100], - borderRadius: BorderRadius.circular(12), - ), - child: Text( - 'Recommended', - style: TextStyle( - fontSize: 10, - color: MixColors.green[700], - fontWeight: FontWeight.w500, - ), - ), - ), - ], - ], - ), - const SizedBox(height: 4), - Text( - description, - style: TextStyle( - fontSize: 12, - color: MixColors.grey[600], - ), - ), - ], - ), - ), - const SizedBox(width: 16), - RemixSwitch( - selected: value, - onChanged: onChanged, - semanticLabel: title, - ), - ], - ), - ); - } -} - -// Helper functions -Widget _buildLabeledSwitch(String label, bool selected, {bool enabled = true}) { - return Column( - children: [ - RemixSwitch( - selected: selected, - enabled: enabled, - onChanged: (bool value) { - if (enabled) { - debugPrint('$label: $value'); - } - }, - semanticLabel: label, - ), - const SizedBox(height: 8), - Text( - label, - style: TextStyle( - fontSize: 12, - color: enabled ? null : MixColors.grey[500], - ), - ), - ], - ); -} - -Widget _buildSimpleSwitch(bool selected, {ValueChanged? onChanged}) { - return RemixSwitch( - selected: selected, - onChanged: onChanged ?? (value) => debugPrint('Switch: $value'), - ); -} \ No newline at end of file diff --git a/demo/lib/components/switch_use_case.dart b/demo/lib/components/switch_use_case.dart deleted file mode 100644 index badd4c91..00000000 --- a/demo/lib/components/switch_use_case.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:demo/helpers/use_case_state.dart'; -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook/widgetbook.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -final _key = GlobalKey(); - -@widgetbook.UseCase( - name: 'Switch Component', - type: RemixSwitch, -) -Widget buildSwitchUseCase(BuildContext context) { - final knobState = WidgetbookState.of(context); - - return KeyedSubtree( - key: _key, - child: Scaffold( - body: Center( - child: RemixSwitch( - selected: context.knobs.boolean(label: 'Toggle', initialValue: true), - enabled: context.knobs.boolean(label: 'Enabled', initialValue: true), - onChanged: (value) => knobState.updateKnob('Toggle', value), - ), - ), - ), - ); -} diff --git a/demo/lib/components/textfield_use_case.dart b/demo/lib/components/textfield_use_case.dart deleted file mode 100644 index 39db0615..00000000 --- a/demo/lib/components/textfield_use_case.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; -import 'package:widgetbook/widgetbook.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -final _key = GlobalKey(); - -@widgetbook.UseCase( - name: 'TextField Component', - type: RemixTextField, -) -Widget buildButtonUseCase(BuildContext context) { - // final iconKnob = context.knobs.iconData(label: 'icons', initialValue: null); - return KeyedSubtree( - key: _key, - child: Scaffold( - body: Center( - child: SizedBox( - width: 300, - child: RemixTextField( - trailing: context.knobs.boolean(label: 'Show Trailing', initialValue: false) - ? RemixIconButton( - icon: Icons.close_rounded, - onPressed: () {}, - ) - : null, - leading: context.knobs.boolean(label: 'Show Leading', initialValue: false) - ? const Icon(Icons.search) - : null, - maxLines: context.knobs.int.input( - label: 'Max Lines', - initialValue: 1, - ), - hintText: context.knobs.string( - label: 'Hint Text', - initialValue: 'Hint Text', - ), - helperText: context.knobs.string( - label: 'Helper Text', - initialValue: 'Helper Text', - ), - ), - ), - ), - ), - ); -} diff --git a/demo/lib/helpers/knob_builder.dart b/demo/lib/helpers/knob_builder.dart deleted file mode 100644 index 64a67894..00000000 --- a/demo/lib/helpers/knob_builder.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:widgetbook/widgetbook.dart'; - -extension KnobsBuilderX on KnobsBuilder { - // Note: Variant methods commented out as they are incompatible with Mix 2.0 - // Mix 2.0 has redesigned the Variant API - Variant is now abstract and - // doesn't have a 'name' property or string constructor. - // These methods would need to be redesigned if variant support is needed. - - // Variant variant(List variants) => list( - // label: 'Variants', - // options: [const Variant('no Variant'), ...variants], - // labelBuilder: (value) => value.name.split('.').last, - // ); - - // Variant variantRaw({ - // required String label, - // required List variants, - // required Variant initialOption, - // }) => - // list( - // label: label, - // options: variants, - // initialOption: initialOption, - // labelBuilder: (value) => value.name.split('.').last, - // ); -} diff --git a/demo/lib/helpers/label_variant_builder.dart b/demo/lib/helpers/label_variant_builder.dart deleted file mode 100644 index a651a657..00000000 --- a/demo/lib/helpers/label_variant_builder.dart +++ /dev/null @@ -1,6 +0,0 @@ -// Note: This file is commented out as it's incompatible with Mix 2.0 -// Mix 2.0 has redesigned the Variant API - Variant no longer has a 'name' property. -// This function would need to be redesigned if variant label building is needed. - -// import 'package:mix/mix.dart'; -// String variantLabelBuilder(Variant value) => value.name.split('.').last; diff --git a/demo/lib/helpers/string.dart b/demo/lib/helpers/string.dart deleted file mode 100644 index 5d929489..00000000 --- a/demo/lib/helpers/string.dart +++ /dev/null @@ -1,5 +0,0 @@ -extension StringExtension on String { - String capitalize() { - return "${this[0].toUpperCase()}${substring(1).toLowerCase()}"; - } -} diff --git a/demo/lib/helpers/use_case_state.dart b/demo/lib/helpers/use_case_state.dart deleted file mode 100644 index 5a652e72..00000000 --- a/demo/lib/helpers/use_case_state.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:widgetbook/widgetbook.dart'; - -extension WidgetBookStateX on WidgetbookState { - void updateKnob(String label, T value) { - updateQueryField( - group: 'knobs', - field: label, - value: '$value', - ); - } -} diff --git a/demo/lib/main.dart b/demo/lib/main.dart deleted file mode 100644 index d363ac45..00000000 --- a/demo/lib/main.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:flutter/material.dart' hide Scaffold, ThemeMode; -import 'package:remix/remix.dart'; -import 'package:widgetbook/widgetbook.dart'; -import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; - -import 'addons/brightness_addon.dart'; -import 'main.directories.g.dart'; - -@widgetbook.App( - cloudAddonsConfigs: { - 'dark fortaleza': [ - BrightnessAddonConfig(WidgetBookBrightness.dark), - ], - 'light fortaleza': [ - BrightnessAddonConfig(WidgetBookBrightness.light), - ], - 'dark base': [ - BrightnessAddonConfig(WidgetBookBrightness.dark), - ], - 'light base': [ - BrightnessAddonConfig(WidgetBookBrightness.light), - ], - }, -) -void main() { - runApp(const HotReload()); -} - -class HotReload extends StatelessWidget { - const HotReload({super.key}); - - @override - Widget build(BuildContext context) { - return Widgetbook( - addons: [ - BrightnessAddon(), - InspectorAddon(), - ], - appBuilder: (context, child) => createRemixScope(child: child), - directories: directories, - ); - } -} diff --git a/demo/lib/main.directories.g.dart b/demo/lib/main.directories.g.dart deleted file mode 100644 index 261b2dd0..00000000 --- a/demo/lib/main.directories.g.dart +++ /dev/null @@ -1,204 +0,0 @@ -// dart format width=80 -// coverage:ignore-file -// ignore_for_file: type=lint -// ignore_for_file: unused_import, prefer_relative_imports, directives_ordering - -// GENERATED CODE - DO NOT MODIFY BY HAND - -// ************************************************************************** -// AppGenerator -// ************************************************************************** - -// ignore_for_file: no_leading_underscores_for_library_prefixes -import 'package:demo/components/avatar_use_case.dart' - as _demo_components_avatar_use_case; -import 'package:demo/components/badge_use_case.dart' - as _demo_components_badge_use_case; -import 'package:demo/components/button_real_world_examples.dart' - as _demo_components_button_real_world_examples; -import 'package:demo/components/button_showcase.dart' - as _demo_components_button_showcase; -import 'package:demo/components/button_use_case.dart' - as _demo_components_button_use_case; -import 'package:demo/components/callout_use_case.dart' - as _demo_components_callout_use_case; -import 'package:demo/components/card_use_case.dart' - as _demo_components_card_use_case; -import 'package:demo/components/checkbox_showcase.dart' - as _demo_components_checkbox_showcase; -import 'package:demo/components/checkbox_use_case.dart' - as _demo_components_checkbox_use_case; -import 'package:demo/components/divider_use_case.dart' - as _demo_components_divider_use_case; -import 'package:demo/components/progress_use_case.dart' - as _demo_components_progress_use_case; -import 'package:demo/components/radio_showcase.dart' - as _demo_components_radio_showcase; -import 'package:demo/components/radio_use_case.dart' - as _demo_components_radio_use_case; -import 'package:demo/components/select.dart' as _demo_components_select; -import 'package:demo/components/slider.dart' as _demo_components_slider; -import 'package:demo/components/spinner_use_case.dart' - as _demo_components_spinner_use_case; -import 'package:demo/components/switch_showcase.dart' - as _demo_components_switch_showcase; -import 'package:demo/components/switch_use_case.dart' - as _demo_components_switch_use_case; -import 'package:demo/components/textfield_use_case.dart' - as _demo_components_textfield_use_case; -import 'package:widgetbook/widgetbook.dart' as _widgetbook; - -final directories = <_widgetbook.WidgetbookNode>[ - _widgetbook.WidgetbookFolder( - name: 'components', - children: [ - _widgetbook.WidgetbookComponent( - name: 'RemixAvatar', - useCases: [ - _widgetbook.WidgetbookUseCase( - name: 'Avatar Component', - builder: _demo_components_avatar_use_case.buildAvatarUseCase, - ) - ], - ), - _widgetbook.WidgetbookComponent( - name: 'RemixBadge', - useCases: [ - _widgetbook.WidgetbookUseCase( - name: 'Badge Component', - builder: _demo_components_badge_use_case.buildAvatarUseCase, - ) - ], - ), - _widgetbook.WidgetbookComponent( - name: 'RemixButton', - useCases: [ - _widgetbook.WidgetbookUseCase( - name: 'Button Component', - builder: _demo_components_button_use_case.buildButtonUseCase, - ), - _widgetbook.WidgetbookUseCase( - name: 'Button Showcase', - builder: _demo_components_button_showcase.buildButtonShowcase, - ), - _widgetbook.WidgetbookUseCase( - name: 'Real World Examples', - builder: _demo_components_button_real_world_examples - .buildButtonRealWorldExamples, - ), - ], - ), - _widgetbook.WidgetbookComponent( - name: 'RemixCallout', - useCases: [ - _widgetbook.WidgetbookUseCase( - name: 'Callout Component', - builder: _demo_components_callout_use_case.buildCalloutUseCase, - ) - ], - ), - _widgetbook.WidgetbookComponent( - name: 'RemixCard', - useCases: [ - _widgetbook.WidgetbookUseCase( - name: 'Card Component', - builder: _demo_components_card_use_case.buildCard, - ) - ], - ), - _widgetbook.WidgetbookComponent( - name: 'RemixCheckbox', - useCases: [ - _widgetbook.WidgetbookUseCase( - name: 'Checkbox Component', - builder: _demo_components_checkbox_use_case.buildCheckboxUseCase, - ), - _widgetbook.WidgetbookUseCase( - name: 'Checkbox Showcase', - builder: _demo_components_checkbox_showcase.buildCheckboxShowcase, - ), - ], - ), - _widgetbook.WidgetbookComponent( - name: 'RemixDivider', - useCases: [ - _widgetbook.WidgetbookUseCase( - name: 'Divider Component', - builder: _demo_components_divider_use_case.buildDivider, - ) - ], - ), - _widgetbook.WidgetbookComponent( - name: 'RemixProgress', - useCases: [ - _widgetbook.WidgetbookUseCase( - name: 'Progress Component', - builder: _demo_components_progress_use_case.buildProgressUseCase, - ) - ], - ), - _widgetbook.WidgetbookComponent( - name: 'RemixRadio', - useCases: [ - _widgetbook.WidgetbookUseCase( - name: 'Radio Component', - builder: _demo_components_radio_use_case.buildRadioUseCase, - ), - _widgetbook.WidgetbookUseCase( - name: 'Radio Showcase', - builder: _demo_components_radio_showcase.buildRadioShowcase, - ), - ], - ), - _widgetbook.WidgetbookComponent( - name: 'RemixSelect', - useCases: [ - _widgetbook.WidgetbookUseCase( - name: 'Select Component', - builder: _demo_components_select.buildSelect, - ) - ], - ), - _widgetbook.WidgetbookComponent( - name: 'RemixSlider', - useCases: [ - _widgetbook.WidgetbookUseCase( - name: 'Slider Component', - builder: _demo_components_slider.buildButtonUseCase, - ) - ], - ), - _widgetbook.WidgetbookComponent( - name: 'RemixSpinner', - useCases: [ - _widgetbook.WidgetbookUseCase( - name: 'Spinner Component', - builder: _demo_components_spinner_use_case.buildSpinnerUseCase, - ) - ], - ), - _widgetbook.WidgetbookComponent( - name: 'RemixSwitch', - useCases: [ - _widgetbook.WidgetbookUseCase( - name: 'Switch Component', - builder: _demo_components_switch_use_case.buildSwitchUseCase, - ), - _widgetbook.WidgetbookUseCase( - name: 'Switch Showcase', - builder: _demo_components_switch_showcase.buildSwitchShowcase, - ), - ], - ), - _widgetbook.WidgetbookComponent( - name: 'RemixTextField', - useCases: [ - _widgetbook.WidgetbookUseCase( - name: 'TextField Component', - builder: _demo_components_textfield_use_case.buildButtonUseCase, - ) - ], - ), - ], - ) -]; diff --git a/demo/lib/previews/button_preview.dart b/demo/lib/previews/button_preview.dart deleted file mode 100644 index d6e32a4b..00000000 --- a/demo/lib/previews/button_preview.dart +++ /dev/null @@ -1,154 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/widget_previews.dart'; -import 'package:remix/remix.dart'; - -import 'preview_helper.dart'; - -@Preview(name: 'Basic Buttons', size: Size(350, 200)) -Widget previewBasicButtons() { - return createRemixPreview( - const Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - RemixButton( - label: 'Primary Button', - onPressed: null, // No-op for preview - ), - SizedBox(height: 12), - RemixButton( - label: 'Button with Icon', - icon: Icons.star, - onPressed: null, - ), - SizedBox(height: 12), - RemixButton( - label: 'Trailing Icon', - icon: Icons.arrow_forward, - onPressed: null, - ), - ], - ), - ); -} - -@Preview(name: 'Button States', size: Size(350, 250)) -Widget previewButtonStates() { - return createRemixPreview( - const Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - RemixButton( - label: 'Enabled Button', - onPressed: null, - ), - SizedBox(height: 12), - RemixButton( - label: 'Disabled Button', - onPressed: null, - ), - SizedBox(height: 12), - RemixButton( - label: 'Loading Button', - loading: true, - onPressed: null, - ), - SizedBox(height: 12), - RemixButton( - label: 'Icon Loading', - icon: Icons.download, - loading: true, - onPressed: null, - ), - ], - ), - ); -} - -@Preview(name: 'Icon-Only Buttons', size: Size(350, 150)) -Widget previewIconButtons() { - return createRemixPreview( - const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - RemixIconButton( - icon: Icons.add, - onPressed: null, - ), - SizedBox(width: 12), - RemixIconButton( - icon: Icons.edit, - onPressed: null, - ), - SizedBox(width: 12), - RemixIconButton( - icon: Icons.delete, - onPressed: null, - ), - SizedBox(width: 12), - RemixIconButton( - icon: Icons.settings, - onPressed: null, - ), - ], - ), - ); -} - -@Preview(name: 'Button Variations', size: Size(400, 300)) -Widget previewButtonVariations() { - return createRemixPreview( - const Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - RemixButton( - label: 'Save', - icon: Icons.save, - onPressed: null, - ), - SizedBox(width: 12), - RemixButton( - label: 'Cancel', - onPressed: null, - ), - ], - ), - SizedBox(height: 16), - RemixButton( - label: 'Download File', - icon: Icons.download, - onPressed: null, - ), - SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - RemixIconButton( - icon: Icons.thumb_up, - onPressed: null, - ), - SizedBox(width: 8), - RemixIconButton( - icon: Icons.thumb_down, - onPressed: null, - ), - SizedBox(width: 8), - RemixIconButton( - icon: Icons.share, - onPressed: null, - ), - ], - ), - SizedBox(height: 16), - RemixButton( - label: 'Processing...', - icon: Icons.sync, - loading: true, - onPressed: null, - ), - ], - ), - ); -} diff --git a/demo/lib/previews/card_preview.dart b/demo/lib/previews/card_preview.dart deleted file mode 100644 index d1ce2d4b..00000000 --- a/demo/lib/previews/card_preview.dart +++ /dev/null @@ -1,261 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/widget_previews.dart'; -import 'package:remix/remix.dart'; - -import 'preview_helper.dart'; - -@Preview(name: 'Basic Card', size: Size(400, 300)) -Widget previewBasicCard() { - return createRemixPreview( - const SizedBox( - width: 350, - child: RemixCard( - child: Padding( - padding: EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - 'Card Title', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 8), - Text( - 'This is a basic card component with some content inside. Cards are great for grouping related information.', - style: TextStyle( - fontSize: 14, - color: MixColors.grey, - ), - ), - ], - ), - ), - ), - ), - ); -} - -@Preview(name: 'Card with Actions', size: Size(400, 350)) -Widget previewCardWithActions() { - return createRemixPreview( - const SizedBox( - width: 350, - child: RemixCard( - child: Padding( - padding: EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Row( - children: [ - Icon(Icons.article, color: MixColors.blue), - SizedBox(width: 12), - Text( - 'Article Title', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - SizedBox(height: 12), - Text( - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', - style: TextStyle( - fontSize: 14, - color: MixColors.grey, - ), - ), - SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - RemixButton( - label: 'Cancel', - onPressed: null, - ), - SizedBox(width: 8), - RemixButton( - label: 'Read More', - onPressed: null, - ), - ], - ), - ], - ), - ), - ), - ), - ); -} - -@Preview(name: 'Profile Card', size: Size(400, 400)) -Widget previewProfileCard() { - return createRemixPreview( - const SizedBox( - width: 350, - child: RemixCard( - child: Padding( - padding: EdgeInsets.all(20.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - CircleAvatar( - radius: 40, - backgroundColor: MixColors.blue, - child: Icon( - Icons.person, - size: 40, - color: MixColors.white, - ), - ), - SizedBox(height: 16), - Text( - 'John Doe', - style: TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 4), - Text( - 'Software Developer', - style: TextStyle( - fontSize: 16, - color: MixColors.grey, - ), - ), - SizedBox(height: 16), - Text( - 'Passionate about creating amazing user experiences and building scalable applications.', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: MixColors.grey, - ), - ), - SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - RemixIconButton( - icon: Icons.email, - onPressed: null, - ), - SizedBox(width: 12), - RemixIconButton( - icon: Icons.phone, - onPressed: null, - ), - SizedBox(width: 12), - RemixIconButton( - icon: Icons.message, - onPressed: null, - ), - ], - ), - ], - ), - ), - ), - ), - ); -} - -@Preview(name: 'Stats Card', size: Size(400, 250)) -Widget previewStatsCard() { - return createRemixPreview( - const SizedBox( - width: 350, - child: RemixCard( - child: Padding( - padding: EdgeInsets.all(20.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - 'Dashboard Statistics', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Column( - children: [ - Text( - '1,234', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: MixColors.blue, - ), - ), - SizedBox(height: 4), - Text( - 'Users', - style: TextStyle( - fontSize: 12, - color: MixColors.grey, - ), - ), - ], - ), - Column( - children: [ - Text( - '567', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: MixColors.green, - ), - ), - SizedBox(height: 4), - Text( - 'Orders', - style: TextStyle( - fontSize: 12, - color: MixColors.grey, - ), - ), - ], - ), - Column( - children: [ - Text( - '\$89,012', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: MixColors.orange, - ), - ), - SizedBox(height: 4), - Text( - 'Revenue', - style: TextStyle( - fontSize: 12, - color: MixColors.grey, - ), - ), - ], - ), - ], - ), - ], - ), - ), - ), - ), - ); -} diff --git a/demo/lib/previews/form_preview.dart b/demo/lib/previews/form_preview.dart deleted file mode 100644 index 2128cf25..00000000 --- a/demo/lib/previews/form_preview.dart +++ /dev/null @@ -1,231 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/widget_previews.dart'; -import 'package:remix/remix.dart'; - -import 'preview_helper.dart'; - -@Preview(name: 'Checkbox States', size: Size(300, 200)) -Widget previewCheckboxStates() { - return createRemixPreview( - const Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - _PreviewCheckbox( - selected: false, - label: 'Unchecked', - ), - SizedBox(height: 12), - _PreviewCheckbox( - selected: true, - label: 'Checked', - ), - SizedBox(height: 12), - _PreviewCheckbox( - selected: false, - enabled: false, - label: 'Disabled', - ), - ], - ), - ); -} - -@Preview(name: 'Switch States', size: Size(300, 200)) -Widget previewSwitchStates() { - return createRemixPreview( - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - RemixSwitch( - selected: true, - onChanged: (value) {}, - ), - const SizedBox(height: 12), - RemixSwitch( - selected: false, - onChanged: (value) {}, - ), - const SizedBox(height: 12), - RemixSwitch( - selected: true, - enabled: false, - onChanged: (value) {}, - ), - const SizedBox(height: 12), - RemixSwitch( - selected: false, - enabled: false, - onChanged: (value) {}, - ), - ], - ), - ); -} - -@Preview(name: 'Radio Group', size: Size(300, 250)) -Widget previewRadioGroup() { - return createRemixPreview( - RemixRadioGroup( - groupValue: 'option1', - onChanged: (value) {}, - child: const Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - _PreviewRadio(value: 'option1', label: 'Selected Option'), - _PreviewRadio(value: 'option2', label: 'Unselected Option'), - _PreviewRadio(value: 'option3', label: 'Another Option'), - _PreviewRadio( - value: 'option4', - label: 'Disabled Option', - enabled: false, - ), - ], - ), - ), - ); -} - -class _PreviewCheckbox extends StatelessWidget { - const _PreviewCheckbox({ - required this.selected, - required this.label, - this.enabled = true, - }); - - final bool selected; - final String label; - final bool enabled; - - @override - Widget build(BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - RemixCheckbox( - selected: selected, - enabled: enabled, - onChanged: (_) {}, - semanticLabel: label, - ), - const SizedBox(width: 8), - Text(label), - ], - ); - } -} - -class _PreviewRadio extends StatelessWidget { - const _PreviewRadio({ - required this.value, - required this.label, - this.enabled = true, - }); - - final String value; - final String label; - final bool enabled; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(4.0), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - RemixRadio( - value: value, - enabled: enabled, - ), - const SizedBox(width: 8), - Text(label), - ], - ), - ); - } -} - -@Preview(name: 'Text Fields', size: Size(400, 350)) -Widget previewTextFields() { - return createRemixPreview( - const SizedBox( - width: 350, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - RemixTextField( - hintText: 'Enter your name', - ), - SizedBox(height: 16), - RemixTextField( - hintText: 'Enter your email', - leading: Icon(Icons.email), - ), - SizedBox(height: 16), - RemixTextField( - hintText: 'Enter password', - obscureText: true, - trailing: Icon(Icons.visibility), - ), - SizedBox(height: 16), - RemixTextField( - hintText: 'This field is disabled', - enabled: false, - ), - ], - ), - ), - ); -} - -@Preview(name: 'Slider Examples', size: Size(350, 200)) -Widget previewSliders() { - return createRemixPreview( - SizedBox( - width: 300, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('Volume: 50%'), - RemixSlider( - value: 0.5, - onChanged: (value) {}, - ), - const SizedBox(height: 20), - const Text('Brightness: 75%'), - RemixSlider( - value: 0.75, - onChanged: (value) {}, - ), - const SizedBox(height: 20), - const Text('Disabled Slider'), - RemixSlider( - value: 0.3, - enabled: false, - onChanged: (value) {}, - ), - ], - ), - ), - ); -} - -@Preview(name: 'Select Dropdown', size: Size(350, 200)) -Widget previewSelect() { - return createRemixPreview( - SizedBox( - width: 300, - child: RemixSelect( - trigger: const RemixSelectTrigger( - placeholder: 'Select an option', - ), - selectedValue: 'option1', - items: const [ - RemixSelectItem(value: 'option1', label: 'First Option'), - RemixSelectItem(value: 'option2', label: 'Second Option'), - RemixSelectItem(value: 'option3', label: 'Third Option'), - ], - onChanged: (value) {}, - ), - ), - ); -} diff --git a/demo/lib/previews/preview_helper.dart b/demo/lib/previews/preview_helper.dart deleted file mode 100644 index de2fa8b9..00000000 --- a/demo/lib/previews/preview_helper.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:remix/remix.dart'; - -/// Helper function for creating consistent widget previews. -/// -/// Wraps the widget with proper Remix theming and Material app context. -/// This ensures all previews have: -/// - Remix tokens and theming -/// - Material design context -/// - Consistent background and centering -/// - Debug banner disabled for clean previews -Widget createRemixPreview(Widget child) { - return createRemixScope( - child: MaterialApp( - debugShowCheckedModeBanner: false, - home: Scaffold( - backgroundColor: MixColors.grey[50], - body: Center( - child: child, - ), - ), - ), - ); -} - -/// Dark mode variant of the preview wrapper. -Widget createRemixPreviewDark(Widget child) { - return createRemixScope( - child: MaterialApp( - debugShowCheckedModeBanner: false, - theme: ThemeData( - brightness: Brightness.dark, - colorScheme: ColorScheme.fromSeed( - seedColor: MixColors.blueGrey, - brightness: Brightness.dark, - ), - ), - home: Scaffold( - backgroundColor: MixColors.black, - body: Center( - child: child, - ), - ), - ), - ); -} diff --git a/demo/macos/Flutter/Flutter-Debug.xcconfig b/demo/macos/Flutter/Flutter-Debug.xcconfig deleted file mode 100644 index 4b81f9b2..00000000 --- a/demo/macos/Flutter/Flutter-Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/demo/macos/Flutter/Flutter-Release.xcconfig b/demo/macos/Flutter/Flutter-Release.xcconfig deleted file mode 100644 index 5caa9d15..00000000 --- a/demo/macos/Flutter/Flutter-Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/demo/macos/Podfile b/demo/macos/Podfile deleted file mode 100644 index b52666a1..00000000 --- a/demo/macos/Podfile +++ /dev/null @@ -1,43 +0,0 @@ -platform :osx, '10.15' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_macos_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) - target 'RunnerTests' do - inherit! :search_paths - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_macos_build_settings(target) - end -end diff --git a/demo/macos/Runner.xcodeproj/project.pbxproj b/demo/macos/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 973ae8c8..00000000 --- a/demo/macos/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,791 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXAggregateTarget section */ - 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; - buildPhases = ( - 33CC111E2044C6BF0003C045 /* ShellScript */, - ); - dependencies = ( - ); - name = "Flutter Assemble"; - productName = FLX; - }; -/* End PBXAggregateTarget section */ - -/* Begin PBXBuildFile section */ - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 60FEB8CFBB5B8F971026C603 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C12D7F3764B263EF5513350D /* Pods_Runner.framework */; }; - 6B46BAAB5323371FD51A3105 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3FE7F80060C6E435B56353B4 /* Pods_RunnerTests.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC10EC2044A3C60003C045; - remoteInfo = Runner; - }; - 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC111A2044C6BA0003C045; - remoteInfo = FLX; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Bundle Framework"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 119319F70E7C394444DC7366 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; - 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; - 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; - 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 3FE7F80060C6E435B56353B4 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 6640A4BF75AA8D1568D26B95 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 8A430C935A42E25DF5E469A3 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 94306D086E177748CC0A9B63 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - A1B795F31CFCAD30EFF7B94A /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; - C12D7F3764B263EF5513350D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - FAE784D6D17FBF1B9B682D61 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 331C80D2294CF70F00263BE5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 6B46BAAB5323371FD51A3105 /* Pods_RunnerTests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EA2044A3C60003C045 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 60FEB8CFBB5B8F971026C603 /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 331C80D6294CF71000263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C80D7294CF71000263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 33BA886A226E78AF003329D5 /* Configs */ = { - isa = PBXGroup; - children = ( - 33E5194F232828860026EE4D /* AppInfo.xcconfig */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, - ); - path = Configs; - sourceTree = ""; - }; - 33CC10E42044A3C60003C045 = { - isa = PBXGroup; - children = ( - 33FAB671232836740065AC1E /* Runner */, - 33CEB47122A05771004F2AC0 /* Flutter */, - 331C80D6294CF71000263BE5 /* RunnerTests */, - 33CC10EE2044A3C60003C045 /* Products */, - 7BC725973F59E594456887D7 /* Pods */, - 62EB7CB52B63813CC1B09258 /* Frameworks */, - ); - sourceTree = ""; - }; - 33CC10EE2044A3C60003C045 /* Products */ = { - isa = PBXGroup; - children = ( - 33CC10ED2044A3C60003C045 /* demo.app */, - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 33CC11242044D66E0003C045 /* Resources */ = { - isa = PBXGroup; - children = ( - 33CC10F22044A3C60003C045 /* Assets.xcassets */, - 33CC10F42044A3C60003C045 /* MainMenu.xib */, - 33CC10F72044A3C60003C045 /* Info.plist */, - ); - name = Resources; - path = ..; - sourceTree = ""; - }; - 33CEB47122A05771004F2AC0 /* Flutter */ = { - isa = PBXGroup; - children = ( - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - ); - path = Flutter; - sourceTree = ""; - }; - 33FAB671232836740065AC1E /* Runner */ = { - isa = PBXGroup; - children = ( - 33CC10F02044A3C60003C045 /* AppDelegate.swift */, - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, - 33E51913231747F40026EE4D /* DebugProfile.entitlements */, - 33E51914231749380026EE4D /* Release.entitlements */, - 33CC11242044D66E0003C045 /* Resources */, - 33BA886A226E78AF003329D5 /* Configs */, - ); - path = Runner; - sourceTree = ""; - }; - 62EB7CB52B63813CC1B09258 /* Frameworks */ = { - isa = PBXGroup; - children = ( - C12D7F3764B263EF5513350D /* Pods_Runner.framework */, - 3FE7F80060C6E435B56353B4 /* Pods_RunnerTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 7BC725973F59E594456887D7 /* Pods */ = { - isa = PBXGroup; - children = ( - 6640A4BF75AA8D1568D26B95 /* Pods-Runner.debug.xcconfig */, - 8A430C935A42E25DF5E469A3 /* Pods-Runner.release.xcconfig */, - FAE784D6D17FBF1B9B682D61 /* Pods-Runner.profile.xcconfig */, - A1B795F31CFCAD30EFF7B94A /* Pods-RunnerTests.debug.xcconfig */, - 94306D086E177748CC0A9B63 /* Pods-RunnerTests.release.xcconfig */, - 119319F70E7C394444DC7366 /* Pods-RunnerTests.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C80D4294CF70F00263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - F2FD480E1394971E74005B24 /* [CP] Check Pods Manifest.lock */, - 331C80D1294CF70F00263BE5 /* Sources */, - 331C80D2294CF70F00263BE5 /* Frameworks */, - 331C80D3294CF70F00263BE5 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 331C80DA294CF71000263BE5 /* PBXTargetDependency */, - ); - name = RunnerTests; - productName = RunnerTests; - productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 33CC10EC2044A3C60003C045 /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 14FD4187A48B8B3FFF8B0A8D /* [CP] Check Pods Manifest.lock */, - 33CC10E92044A3C60003C045 /* Sources */, - 33CC10EA2044A3C60003C045 /* Frameworks */, - 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, - 3399D490228B24CF009A79C7 /* ShellScript */, - F5CF086EE6C67FF2CC959A83 /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 33CC11202044C79F0003C045 /* PBXTargetDependency */, - ); - name = Runner; - productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* demo.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 33CC10E52044A3C60003C045 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C80D4294CF70F00263BE5 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = 33CC10EC2044A3C60003C045; - }; - 33CC10EC2044A3C60003C045 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.Sandbox = { - enabled = 1; - }; - }; - }; - 33CC111A2044C6BA0003C045 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 33CC10E42044A3C60003C045; - productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 33CC10EC2044A3C60003C045 /* Runner */, - 331C80D4294CF70F00263BE5 /* RunnerTests */, - 33CC111A2044C6BA0003C045 /* Flutter Assemble */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 331C80D3294CF70F00263BE5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EB2044A3C60003C045 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 14FD4187A48B8B3FFF8B0A8D /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 3399D490228B24CF009A79C7 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; - }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, - ); - outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; - }; - F2FD480E1394971E74005B24 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - F5CF086EE6C67FF2CC959A83 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 331C80D1294CF70F00263BE5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10E92044A3C60003C045 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC10EC2044A3C60003C045 /* Runner */; - targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; - }; - 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; - targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 33CC10F52044A3C60003C045 /* Base */, - ); - name = MainMenu.xib; - path = Runner; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 331C80DB294CF71000263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = A1B795F31CFCAD30EFF7B94A /* Pods-RunnerTests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.demo.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/demo.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/demo"; - }; - name = Debug; - }; - 331C80DC294CF71000263BE5 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 94306D086E177748CC0A9B63 /* Pods-RunnerTests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.demo.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/demo.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/demo"; - }; - name = Release; - }; - 331C80DD294CF71000263BE5 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 119319F70E7C394444DC7366 /* Pods-RunnerTests.profile.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.demo.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/demo.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/demo"; - }; - name = Profile; - }; - 338D0CE9231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Profile; - }; - 338D0CEA231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Profile; - }; - 338D0CEB231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Profile; - }; - 33CC10F92044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 33CC10FA2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Release; - }; - 33CC10FC2044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 33CC10FD2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 33CC111C2044C6BA0003C045 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 33CC111D2044C6BA0003C045 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 331C80DB294CF71000263BE5 /* Debug */, - 331C80DC294CF71000263BE5 /* Release */, - 331C80DD294CF71000263BE5 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10F92044A3C60003C045 /* Debug */, - 33CC10FA2044A3C60003C045 /* Release */, - 338D0CE9231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10FC2044A3C60003C045 /* Debug */, - 33CC10FD2044A3C60003C045 /* Release */, - 338D0CEA231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC111C2044C6BA0003C045 /* Debug */, - 33CC111D2044C6BA0003C045 /* Release */, - 338D0CEB231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 33CC10E52044A3C60003C045 /* Project object */; -} diff --git a/demo/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/demo/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/demo/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/demo/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/demo/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index a6e20c26..00000000 --- a/demo/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/demo/macos/Runner.xcworkspace/contents.xcworkspacedata b/demo/macos/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14..00000000 --- a/demo/macos/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/demo/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/demo/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/demo/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/demo/macos/Runner/AppDelegate.swift b/demo/macos/Runner/AppDelegate.swift deleted file mode 100644 index b3c17614..00000000 --- a/demo/macos/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Cocoa -import FlutterMacOS - -@main -class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } - - override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { - return true - } -} diff --git a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index a2ec33f1..00000000 --- a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" - }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png deleted file mode 100644 index 82b6f9d9..00000000 Binary files a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png and /dev/null differ diff --git a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png deleted file mode 100644 index 13b35eba..00000000 Binary files a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png and /dev/null differ diff --git a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png deleted file mode 100644 index 0a3f5fa4..00000000 Binary files a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png and /dev/null differ diff --git a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png deleted file mode 100644 index bdb57226..00000000 Binary files a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png and /dev/null differ diff --git a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png deleted file mode 100644 index f083318e..00000000 Binary files a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png and /dev/null differ diff --git a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png deleted file mode 100644 index 326c0e72..00000000 Binary files a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png and /dev/null differ diff --git a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png deleted file mode 100644 index 2f1632cf..00000000 Binary files a/demo/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png and /dev/null differ diff --git a/demo/macos/Runner/Base.lproj/MainMenu.xib b/demo/macos/Runner/Base.lproj/MainMenu.xib deleted file mode 100644 index 80e867a4..00000000 --- a/demo/macos/Runner/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,343 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/demo/macos/Runner/Configs/AppInfo.xcconfig b/demo/macos/Runner/Configs/AppInfo.xcconfig deleted file mode 100644 index 0899fc39..00000000 --- a/demo/macos/Runner/Configs/AppInfo.xcconfig +++ /dev/null @@ -1,14 +0,0 @@ -// Application-level settings for the Runner target. -// -// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the -// future. If not, the values below would default to using the project name when this becomes a -// 'flutter create' template. - -// The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = demo - -// The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.example.demo - -// The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright Β© 2024 com.example. All rights reserved. diff --git a/demo/macos/Runner/Configs/Debug.xcconfig b/demo/macos/Runner/Configs/Debug.xcconfig deleted file mode 100644 index 36b0fd94..00000000 --- a/demo/macos/Runner/Configs/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Debug.xcconfig" -#include "Warnings.xcconfig" diff --git a/demo/macos/Runner/Configs/Release.xcconfig b/demo/macos/Runner/Configs/Release.xcconfig deleted file mode 100644 index dff4f495..00000000 --- a/demo/macos/Runner/Configs/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Release.xcconfig" -#include "Warnings.xcconfig" diff --git a/demo/macos/Runner/Configs/Warnings.xcconfig b/demo/macos/Runner/Configs/Warnings.xcconfig deleted file mode 100644 index 42bcbf47..00000000 --- a/demo/macos/Runner/Configs/Warnings.xcconfig +++ /dev/null @@ -1,13 +0,0 @@ -WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings -GCC_WARN_UNDECLARED_SELECTOR = YES -CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES -CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES -CLANG_WARN_PRAGMA_PACK = YES -CLANG_WARN_STRICT_PROTOTYPES = YES -CLANG_WARN_COMMA = YES -GCC_WARN_STRICT_SELECTOR_MATCH = YES -CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES -GCC_WARN_SHADOW = YES -CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/demo/macos/Runner/DebugProfile.entitlements b/demo/macos/Runner/DebugProfile.entitlements deleted file mode 100644 index 4ec85ba6..00000000 --- a/demo/macos/Runner/DebugProfile.entitlements +++ /dev/null @@ -1,14 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.network.client - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - - diff --git a/demo/macos/Runner/Info.plist b/demo/macos/Runner/Info.plist deleted file mode 100644 index 4789daa6..00000000 --- a/demo/macos/Runner/Info.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/demo/macos/Runner/MainFlutterWindow.swift b/demo/macos/Runner/MainFlutterWindow.swift deleted file mode 100644 index 3cc05eb2..00000000 --- a/demo/macos/Runner/MainFlutterWindow.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Cocoa -import FlutterMacOS - -class MainFlutterWindow: NSWindow { - override func awakeFromNib() { - let flutterViewController = FlutterViewController() - let windowFrame = self.frame - self.contentViewController = flutterViewController - self.setFrame(windowFrame, display: true) - - RegisterGeneratedPlugins(registry: flutterViewController) - - super.awakeFromNib() - } -} diff --git a/demo/macos/Runner/Release.entitlements b/demo/macos/Runner/Release.entitlements deleted file mode 100644 index 08ba3a3f..00000000 --- a/demo/macos/Runner/Release.entitlements +++ /dev/null @@ -1,10 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.network.client - - - diff --git a/demo/macos/RunnerTests/RunnerTests.swift b/demo/macos/RunnerTests/RunnerTests.swift deleted file mode 100644 index 5418c9f5..00000000 --- a/demo/macos/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -import FlutterMacOS -import Cocoa -import XCTest - -class RunnerTests: XCTestCase { - - func testExample() { - // If you add code to the Runner application, consider adding tests here. - // See https://developer.apple.com/documentation/xctest for more information about using XCTest. - } - -} diff --git a/demo/pubspec.yaml b/demo/pubspec.yaml deleted file mode 100644 index 85c942f5..00000000 --- a/demo/pubspec.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: demo -description: "A new Flutter project." - -publish_to: "none" - -version: 1.0.0+1 - -environment: - sdk: ">=3.6.0 <4.0.0" - -dependencies: - flutter: - sdk: flutter - - cupertino_icons: ^1.0.2 - widgetbook_annotation: ^3.1.0 - widgetbook: ^3.8.0 - remix: - path: ../ - - mix: 2.0.0-dev.4 - -dev_dependencies: - flutter_test: - sdk: flutter - - flutter_lints: ^4.0.0 - widgetbook_generator: ^3.8.0 - build_runner: ^2.4.9 - -flutter: - uses-material-design: true diff --git a/demo/scripts/preview.sh b/demo/scripts/preview.sh deleted file mode 100755 index 690a3a2c..00000000 --- a/demo/scripts/preview.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -# Navigate to the demo directory (parent of scripts) -cd "$(dirname "$0")/.." - -echo "πŸš€ Starting Remix Widget Preview..." -echo "πŸ“ Running from: $(pwd)" -echo "" - -# Check if Flutter is available -if ! command -v flutter &> /dev/null -then - echo "❌ Flutter could not be found. Please ensure Flutter is installed and in your PATH." - exit 1 -fi - -# Check Flutter version -echo "πŸ“‹ Flutter Version:" -flutter --version | head -1 - -echo "" -echo "πŸ”§ Starting widget preview server..." -echo "πŸ’‘ This will open in Chrome browser automatically" -echo "πŸ“ Available previews:" -echo " β€’ Accordion (Basic, with Icons, Pre-expanded, Rich Content)" -echo " β€’ Buttons (Basic, States, Icon-only, Variations)" -echo " β€’ Cards (Basic, with Actions, Profile, Stats)" -echo " β€’ Form Components (Checkbox, Switch, Radio, TextField, Slider, Select)" -echo "" -echo "πŸ›‘ Press Ctrl+C to stop the preview server" -echo "" - -# Start the widget preview -flutter widget-preview start \ No newline at end of file diff --git a/demo/test/widget_test.dart b/demo/test/widget_test.dart deleted file mode 100644 index 0ecea136..00000000 --- a/demo/test/widget_test.dart +++ /dev/null @@ -1,11 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. -import 'package:flutter_test/flutter_test.dart'; - -void main() { - test('description', () => expect(true, true)); -} diff --git a/demo/web/favicon.png b/demo/web/favicon.png deleted file mode 100644 index 8aaa46ac..00000000 Binary files a/demo/web/favicon.png and /dev/null differ diff --git a/demo/web/icons/Icon-192.png b/demo/web/icons/Icon-192.png deleted file mode 100644 index b749bfef..00000000 Binary files a/demo/web/icons/Icon-192.png and /dev/null differ diff --git a/demo/web/icons/Icon-512.png b/demo/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48d..00000000 Binary files a/demo/web/icons/Icon-512.png and /dev/null differ diff --git a/demo/web/icons/Icon-maskable-192.png b/demo/web/icons/Icon-maskable-192.png deleted file mode 100644 index eb9b4d76..00000000 Binary files a/demo/web/icons/Icon-maskable-192.png and /dev/null differ diff --git a/demo/web/icons/Icon-maskable-512.png b/demo/web/icons/Icon-maskable-512.png deleted file mode 100644 index d69c5669..00000000 Binary files a/demo/web/icons/Icon-maskable-512.png and /dev/null differ diff --git a/demo/web/index.html b/demo/web/index.html deleted file mode 100644 index 1a98da7d..00000000 --- a/demo/web/index.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - demo - - - - - - - - - - diff --git a/demo/web/manifest.json b/demo/web/manifest.json deleted file mode 100644 index 238a284b..00000000 --- a/demo/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "demo", - "short_name": "demo", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} diff --git a/pubspec.lock b/pubspec.lock index 6c82a8d5..d152859e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -387,7 +387,7 @@ packages: source: hosted version: "2.0.0-dev.4" mix_annotations: - dependency: "direct main" + dependency: transitive description: name: mix_annotations sha256: "6ec624a3268973e8ca1b3cbf0f6c661a064313c3a6de46546491703fd5747638" @@ -406,10 +406,10 @@ packages: dependency: "direct main" description: name: naked_ui - sha256: "3b0ee4a19a781df393e8466bc5a6be6f46cbcbef17b6b4b70cb7c5d6286ab5a3" + sha256: d6b0868cfc84cab94f252b92f03c42a0e8acc5ec4beab412f39be0164d564398 url: "https://pub.dev" source: hosted - version: "0.2.0-beta.3" + version: "0.2.0-beta.5" package_config: dependency: transitive description: diff --git a/test_driver/integration_test.dart b/test_driver/integration_test.dart deleted file mode 100644 index 6854dea6..00000000 --- a/test_driver/integration_test.dart +++ /dev/null @@ -1,3 +0,0 @@ -import 'package:integration_test/integration_test_driver.dart'; - -Future main() => integrationDriver(); \ No newline at end of file