Skip to content

docs(claude-plugin): add themed-button, themed-alert and themed-snack…

78e6272
Select commit
Loading
Failed to load commit list.
Sign in for the full log view
Merged

feat(claude-plugin): restructure skills and add themed-button, themed-alert, themed-snackbar; fix ThemedColorPicker bugs #133

docs(claude-plugin): add themed-button, themed-alert and themed-snack…
78e6272
Select commit
Loading
Failed to load commit list.
GitHub Actions / Unit Tests succeeded Apr 22, 2026 in 1s

402 passed, 0 failed and 0 skipped

Tests passed successfully

βœ…Β test-results.json

402 tests were completed in 73s with 402 passed, 0 failed and 0 skipped.

Test suite Passed Failed Skipped Time
test/alerts_test.dart 3βœ… 713ms
test/color_test.dart 32βœ… 84ms
test/colorblind_filter_test.dart 38βœ… 102ms
test/datetime_extension_test.dart 3βœ… 35ms
test/datetime_test.dart 26βœ… 122ms
test/duration_test.dart 12βœ… 58ms
test/file_utilities_test.dart 25βœ… 86ms
test/grid_test.dart 7βœ… 37ms
test/helpers_test.dart 14βœ… 53ms
test/orm_test.dart 21βœ… 59ms
test/password_input_test.dart 7βœ… 1s
test/separator_extension_test.dart 24βœ… 68ms
test/table_controller_test.dart 9βœ… 43ms
test/theme_color_test.dart 26βœ… 86ms
test/widgets/alerts_test.dart 3βœ… 707ms
test/widgets/avatar_test.dart 18βœ… 1s
test/widgets/button_test.dart 7βœ… 1s
test/widgets/chip_test.dart 2βœ… 557ms
test/widgets/color_picker_test.dart 12βœ… 2s
test/widgets/field_error_test.dart 8βœ… 713ms
test/widgets/layo_test.dart 3βœ… 697ms
test/widgets/number_input_test.dart 31βœ… 2s
test/widgets/responsive_row_test.dart 36βœ… 999ms
test/widgets/table2_test.dart 14βœ… 16s
test/widgets/tabs_test.dart 21βœ… 2s

βœ…Β test/alerts_test.dart

ThemedAlert widget
  βœ… renders info alert
  βœ… renders success alert
  βœ… renders custom alert with icon and color

βœ…Β test/color_test.dart

toHex()
  βœ… converts black to #000000
  βœ… converts white to #FFFFFF
  βœ… converts kAccentColor (#FF8200)
  βœ… converts kPrimaryColor (#001e60)
  βœ… outputs uppercase hex
  βœ… ignores alpha channel
  βœ… hex getter is alias for toHex()
toHexWithAlpha()
  βœ… includes full alpha (#FFFFFFFF for white)
  βœ… includes zero alpha (#00000000 for transparent)
  βœ… includes partial alpha (#80FF8200)
  βœ… alpha comes first in AARRGGBB format
  βœ… hexWithAlpha getter is alias for toHexWithAlpha()
toInt()
  βœ… converts to ARGB integer
  βœ… handles alpha channel correctly
  βœ… black is 0xFF000000
  βœ… white is 0xFFFFFFFF
  βœ… transparent is 0x00000000
fromHex()
  βœ… parses black #000000
  βœ… parses white #FFFFFF
  βœ… parses accent color #FF8200
  βœ… parses primary color #001E60
  βœ… parses lowercase hex #ff8200
  βœ… sets alpha to 255 (fully opaque)
fromHexWithAlpha()
  βœ… parses full alpha #FFFFFFFF
  βœ… parses zero alpha #00000000
  βœ… parses partial alpha #80FF8200
  βœ… parses alpha first in AARRGGBB format
Round-trip conversions
  βœ… Color -> toHex() -> fromHex() -> Color preserves RGB
  βœ… Color -> toHexWithAlpha() -> fromHexWithAlpha() -> Color preserves ARGB
  βœ… Color -> toInt() -> Color() preserves exact value
JSON aliases
  βœ… toJson() is equivalent to toHex()
  βœ… fromJson() is equivalent to fromHex()

βœ…Β test/colorblind_filter_test.dart

protanopiaFilter()
  βœ… strength 0.0 returns identity matrix
  βœ… strength 1.0 returns full filter matrix
  βœ… strength 0.5 returns interpolated matrix
  βœ… has exactly 20 elements
  βœ… handles boundary strength values
protanomalyFilter()
  βœ… strength 0.0 returns identity matrix
  βœ… strength 1.0 returns full filter matrix
  βœ… strength 0.5 returns interpolated matrix
  βœ… has exactly 20 elements
deuteranopiaFilter()
  βœ… strength 0.0 returns identity matrix
  βœ… strength 1.0 returns full filter matrix
  βœ… strength 0.5 returns interpolated matrix
  βœ… has exactly 20 elements
deuteranomalyFilter()
  βœ… strength 0.0 returns identity matrix
  βœ… strength 1.0 returns full filter matrix
  βœ… strength 0.5 returns interpolated matrix
  βœ… has exactly 20 elements
tritanopiaFilter()
  βœ… strength 0.0 returns identity matrix
  βœ… strength 1.0 returns full filter matrix
  βœ… strength 0.5 returns interpolated matrix
  βœ… has exactly 20 elements
tritanomalyFilter()
  βœ… strength 0.0 returns identity matrix
  βœ… strength 1.0 returns full filter matrix
  βœ… strength 0.5 returns interpolated matrix
  βœ… has exactly 20 elements
ColorblindFilter extension
  βœ… normal mode returns identity matrix
  βœ… protanopia mode creates ColorFilter from protanopia matrix
  βœ… protanomaly mode creates ColorFilter from protanomaly matrix
  βœ… deuteranopia mode creates ColorFilter from deuteranopia matrix
  βœ… deuteranomaly mode creates ColorFilter from deuteranomaly matrix
  βœ… tritanopia mode creates ColorFilter from tritanopia matrix
  βœ… tritanomaly mode creates ColorFilter from tritanomaly matrix
  βœ… all modes accept strength parameter
Matrix interpolation behavior
  βœ… increasing strength gradually changes matrix values
  βœ… all filters preserve alpha channel (elements 15-19)
Edge cases
  βœ… negative strength handled (treated as 0 or clamped)
  βœ… strength > 1.0 handled (extrapolates or clamped)
  βœ… all filters produce distinct matrices at full strength

βœ…Β test/datetime_extension_test.dart

DateTimeExtension
  βœ… secondsSinceEpoch returns correct value
  βœ… thisWeek and lastWeek return correct dates
  βœ… thisMonth and lastMonth return correct dates

βœ…Β test/datetime_test.dart

thisWeek / lastWeek
  βœ… returns correct week boundaries
  βœ… handles Monday correctly
  βœ… handles Sunday correctly
thisMonth / lastMonth
  βœ… returns correct month boundaries for August
  βœ… returns correct lastMonth boundaries
  βœ… handles February in leap year
  βœ… handles February in non-leap year
  βœ… handles January lastMonth wraps to previous year
secondsSinceEpoch
  βœ… converts milliseconds to seconds
  βœ… handles epoch zero
format
  βœ… %Y full year
  βœ… %y two-digit year
  βœ… %m zero-padded month
  βœ… %d zero-padded day
  βœ… %H 24-hour format
  βœ… %I 12-hour format
  βœ… %p AM/PM indicator
  βœ… %M zero-padded minute
  βœ… %S zero-padded second
  βœ… %A full weekday name
  βœ… %a abbreviated weekday name
  βœ… %B full month name
  βœ… %b abbreviated month name
  βœ… %% literal percent
  βœ… combined pattern
  βœ… %I shows 12 for noon/midnight

βœ…Β test/duration_test.dart

Duration.humanize
  βœ… single unit
  βœ… singular unit
  βœ… two units joined with conjunction
  βœ… three units with delimiter and conjunction
  βœ… zero duration returns smallest unit with 0
  βœ… negative duration uses absolute value
  βœ… filters out zero-value units
  βœ… lastPrefixComma adds comma before conjunction
  βœ… custom delimiter
  βœ… custom units subset
  βœ… zero duration with seconds in units
  βœ… large duration includes days and months

βœ…Β test/file_utilities_test.dart

ThemedFile
  βœ… creates file with name and bytes
  βœ… creates file with optional path
  βœ… toString() includes name and size
ThemedFile.mimeType
  βœ… detects PNG image
  βœ… detects JPG image
  βœ… detects JPEG image
  βœ… detects GIF image
  βœ… detects SVG image
  βœ… detects PDF document
  βœ… detects custom .lc extension
  βœ… uses path over name when both provided
  βœ… handles unknown extension
  βœ… case insensitive extension detection
parseFileToBase64()
  βœ… converts bytes to base64
  βœ… includes file name in result
  βœ… includes mime type in result
  βœ… returns null when mime type cannot be determined
  βœ… handles empty file
  βœ… round-trip base64 encoding/decoding
parseFileToByteArray()
  βœ… returns file bytes as List<int>
  βœ… handles empty file
  βœ… preserves byte values
  βœ… returns a copy (new list)
globalMimeResolver
  βœ… includes custom .lc extension
  βœ… still supports standard extensions

βœ…Β test/grid_test.dart

Sizes.gridSize
  βœ… each enum returns correct column count
Sizes.boxWidth
  βœ… col12 returns full width
  βœ… col6 returns half width
  βœ… col4 returns one-third width
  βœ… col3 returns one-quarter width
  βœ… col1 returns 1/12 of width
  βœ… formula is (width / 12) * gridSize

βœ…Β test/helpers_test.dart

useBlack
  βœ… returns true for white (high luminance)
  βœ… returns false for black (low luminance)
  βœ… returns true for yellow (high luminance)
  βœ… returns false for dark blue (low luminance)
  βœ… respects custom tolerance
validateColor
  βœ… returns black for light colors
  βœ… returns white for dark colors
getPrimaryColor
  βœ… returns kPrimaryColor when null
  βœ… returns provided color when non-null
getAccentColor
  βœ… returns kAccentColor when null
  βœ… returns provided color when non-null
generateSwatch
  βœ… without shader all shades are the same color
  βœ… with shader shades have increasing alpha
  βœ… swatch has all 10 shade levels

βœ…Β test/orm_test.dart

setErrors() and getErrors()
  βœ… stores and retrieves errors correctly
  βœ… retrieves empty list for non-existent key
  βœ… handles multiple errors for same key
  βœ… replaces existing errors when setErrors called again
hasErrors()
  βœ… returns true when key has errors
  βœ… returns false when key has no errors
  βœ… returns false for non-existent key
hasContainerErrors()
  βœ… returns true when any key starts with prefix
  βœ… returns false when no keys match prefix
  βœ… exact match works as prefix
  βœ… returns false when errors map is empty
Error code handling without i18n
  βœ… returns error code as fallback when no i18n set
  βœ… minLength error includes parameters in fallback
  βœ… maxLength error includes parameters in fallback
  βœ… minLength with multiple parameters in fallback
Multiple error codes
  βœ… handles mix of standard and length errors
Raw errors access
  βœ… rawErrors returns the internal error map
  βœ… rawErrors is empty after setting empty map
Edge cases
  βœ… handles empty error list for key
  βœ… handles error with empty code
  βœ… handles special characters in error keys

βœ…Β test/password_input_test.dart

ThemedPasswordInput
  βœ… renders with label
  βœ… toggles password visibility on eye icon tap
  βœ… shows shield check icon for valid password
  βœ… shows close circle icon for invalid password
  βœ… shows close circle icon for empty password
  βœ… hides strength indicator when showLevels is false
  βœ… calls onChanged when text is entered

βœ…Β test/separator_extension_test.dart

num.w (width)
  βœ… creates SizedBox with width
  βœ… handles integer values
  βœ… handles double values
  βœ… handles zero
  βœ… width alias is equivalent to w
num.h (height)
  βœ… creates SizedBox with height
  βœ… handles integer values
  βœ… handles double values
  βœ… handles zero
  βœ… height alias is equivalent to h
num.wh (square)
  βœ… creates SizedBox with equal width and height
  βœ… handles integer values
  βœ… handles double values
  βœ… handles zero
  βœ… square alias is equivalent to wh
Different num types
  βœ… works with int
  βœ… works with double
  βœ… works with num variable
Edge cases
  βœ… handles very small values
  βœ… handles very large values
  βœ… handles negative values (though unusual in UI)
Common usage patterns
  βœ… can be used for spacing between widgets
  βœ… can create responsive spacing
  βœ… can create square placeholders

βœ…Β test/table_controller_test.dart

ThemedTable2Controller
  βœ… addListener adds listener to list
  βœ… removeListener removes specific listener
  βœ… clearListeners removes all listeners
  βœ… sort triggers ThemedTable2SortEvent with correct parameters
  βœ… sort with default parameters
  βœ… refresh triggers ThemedTable2RefreshEvent
  βœ… multiple listeners all receive events
  βœ… dispose clears all listeners
  βœ… events fire in order listeners were added

βœ…Β test/theme_color_test.dart

getThemeColor() - Predefined themes
  βœ… PINK returns Colors.pink
  βœ… RED returns Colors.red
  βœ… DEEPORANGE returns Colors.deepOrange
  βœ… ORANGE returns Colors.orange
  βœ… AMBER returns Colors.amber
  βœ… YELLOW returns Colors.yellow
  βœ… LIME returns Colors.lime
  βœ… LIGHTGREEN returns Colors.lightGreen
  βœ… GREEN returns Colors.green
  βœ… TEAL returns Colors.teal
  βœ… CYAN returns Colors.cyan
  βœ… LIGHTBLUE returns Colors.lightBlue
  βœ… BLUE returns Colors.blue
  βœ… INDIGO returns Colors.indigo
  βœ… DEEPBLUE returns Colors.deepPurple
  βœ… PURPLE returns Colors.purple
  βœ… BLUEGREY returns Colors.blueGrey
  βœ… GREY returns Colors.grey
  βœ… BROWN returns Colors.brown
getThemeColor() - CUSTOM theme
  βœ… CUSTOM with provided color generates swatch from that color
  βœ… CUSTOM without explicit color uses kPrimaryColor
getThemeColor() - Invalid/default handling
  βœ… Invalid theme returns swatch from kPrimaryColor
  βœ… Empty string theme returns swatch from kPrimaryColor
  βœ… Lowercase theme name does not match (case-sensitive)
getThemeColor() - Return type validation
  βœ… All valid themes return MaterialColor type
  βœ… MaterialColor has all required shades (50-900)

βœ…Β test/widgets/alerts_test.dart

ThemedAlert widget
  βœ… renders info alert
  βœ… renders success alert
  βœ… renders custom alert with icon and color

βœ…Β test/widgets/avatar_test.dart

ThemedAvatar - Basic rendering
  βœ… renders with default size
  βœ… renders with custom size
  βœ… renders fallback initials when no avatar provided
  βœ… renders NA when name is null
ThemedAvatar - Icon rendering
  βœ… renders icon when provided
  βœ… icon size is 70% of avatar size by default
  βœ… respects custom icon size
ThemedAvatar - Name cleaning
  βœ… cleans special characters from name
  βœ… handles single character name
  βœ… returns NA for name with only special characters
  βœ… takes first 2 characters and uppercases
ThemedAvatar - Tap handlers
  βœ… calls onTap when tapped
  βœ… calls onLongTap when long pressed
  βœ… calls onSecondaryTap when secondary tapped
ThemedAvatar - Elevation and styling
  βœ… applies custom color
  βœ… elevation must be between 0 and 5
  βœ… radius must be greater than or equal to 0
ThemedAvatar - Priority order
  βœ… icon takes priority over name fallback

βœ…Β test/widgets/button_test.dart

ThemedButton widget
  βœ… renders with labelText
  βœ… renders with icon
  βœ… renders as disabled
  βœ… renders loading state
  βœ… renders with custom color
  βœ… renders with different styles
  βœ… renders with factory constructors

βœ…Β test/widgets/chip_test.dart

ThemedChip widget
  βœ… renders with label
  βœ… renders with custom color

βœ…Β test/widgets/color_picker_test.dart

ThemedColorPicker rendering
  βœ… renders without crashing
  βœ… shows label text
  βœ… shows hex value in text field
  βœ… shows kPrimaryColor hex when value is null
  βœ… shows color swatch in prefix
ThemedColorPicker disabled
  βœ… disabled picker does not open dialog on tap
  βœ… enabled picker opens dialog on tap
ThemedColorPicker lifecycle
  βœ… mounts and unmounts without errors
  βœ… repeated mount/unmount cycles do not throw
  βœ… didUpdateWidget updates text field when value changes externally
  βœ… didUpdateWidget resets to kPrimaryColor when value changes to null
  βœ… didUpdateWidget does not rebuild when same value is passed

βœ…Β test/widgets/field_error_test.dart

ThemedFieldDisplayError
  βœ… displays single error message
  βœ… displays multiple errors joined by comma
  βœ… hides errors when hideDetails is true
  βœ… shows nothing when errors list is empty
  βœ… applies custom padding
  βœ… applies maxLines constraint
  βœ… error text is red
  βœ… default maxLines is 1

βœ…Β test/widgets/layo_test.dart

Layo widget
  βœ… throws assertion error for invalid elevation
  βœ… renders with default values
  βœ… renders with custom emotion

βœ…Β test/widgets/number_input_test.dart

ThemedNumberInput rendering
  βœ… renders without crashing
  βœ… shows label text
  βœ… shows initial value formatted in the text field
  βœ… shows empty field when value is null
  βœ… shows suffixText when provided
  βœ… shows prefixText when provided
  βœ… shows required asterisk when isRequired is true
  βœ… shows error text when errors list is non-empty
  βœ… hides error space when hideDetails is true
ThemedNumberInput onChanged via keyboard
  βœ… calls onChanged with parsed num when user types a number
  βœ… calls onChanged(null) when user clears the field
  βœ… does NOT call onChanged when user types only a minus sign
  βœ… does NOT call onChanged when input cannot be parsed (C3 regression)
  βœ… calls onChanged with negative number
ThemedNumberInput step buttons
  βœ… increment button increases value by step
  βœ… decrement button decreases value by step
  βœ… step defaults to 1 when not provided
  βœ… value starts at 0 when null and step button is tapped
  βœ… increment is disabled at maximum β€” does not call onChanged
  βœ… decrement is disabled at minimum β€” does not call onChanged
  βœ… step buttons are hidden when hidePrefixSuffixActions is true
  βœ… step buttons are hidden when disabled is true
ThemedNumberInput cursor position after step
  βœ… cursor is at end after incrementing from 9 to 10 (digit count changes)
  βœ… cursor is at end after incrementing from 99 to 100
  βœ… cursor is at end after decrementing from 10 to 9 (digit count shrinks)
  βœ… cursor is at end after incrementing into thousands (999 to 1,000)
ThemedNumberInput decimal separators
  βœ… dot separator formats 1234.5 as "1,234.5"
  βœ… comma separator formats 1234.5 as "1.234,5"
ThemedNumberInput lifecycle
  βœ… widget mounts and unmounts without errors
  βœ… repeated mount/unmount cycles do not throw
  βœ… controller text clears when value changes to null

βœ…Β test/widgets/responsive_row_test.dart

ResponsiveRow
  βœ… Renders basic ResponsiveRow with children
  βœ… ResponsiveRow with empty children renders empty Wrap
  βœ… ResponsiveRow with single child
  βœ… ResponsiveRow respects spacing parameter
  βœ… ResponsiveRow respects spacing = 0
  βœ… ResponsiveRow default spacing is 0
  βœ… ResponsiveRow respects mainAxisAlignment
  βœ… ResponsiveRow respects crossAxisAlignment
  βœ… ResponsiveRow has full width (width: double.infinity)
  βœ… ResponsiveRow.builder creates correct number of children
  βœ… ResponsiveRow.builder with itemCount=0
  βœ… ResponsiveRow.builder respects mainAxisAlignment
  βœ… ResponsiveRow.builder respects spacing
  βœ… ResponsiveRow uses Wrap as layout widget
  βœ… ResponsiveRow.builder with large itemCount
ResponsiveCol
  βœ… ResponsiveCol renders child
  βœ… ResponsiveCol uses xs by default
  βœ… ResponsiveCol falls back to xs if sm is null
  βœ… ResponsiveCol with all breakpoints specified
  βœ… ResponsiveCol uses LayoutBuilder for responsive sizing
  βœ… ResponsiveCol preserves child widget type
  βœ… ResponsiveCol with different size values
Sizes enum
  βœ… Sizes.col1 returns gridSize 1
  βœ… Sizes.col6 returns gridSize 6
  βœ… Sizes.col12 returns gridSize 12
  βœ… boxWidth calculates correct width for col6 at 1200px
  βœ… boxWidth calculates correct width for col12 at 1200px
  βœ… boxWidth calculates correct width for col3 at 600px
  βœ… boxWidth calculates correct width for col1 at 1200px
  βœ… boxWidth with col2 at 1200px equals 200
  βœ… boxWidth with col4 at 800px equals 266.67
  βœ… All sizes have valid gridSize
ResponsiveRow and ResponsiveCol integration
  βœ… ResponsiveRow with multiple ResponsiveCol children renders correctly
  βœ… ResponsiveRow with many children
  βœ… ResponsiveRow.builder with all parameters
  βœ… ResponsiveCol with ResponsiveRow preserves layout structure

βœ…Β test/widgets/table2_test.dart

ThemedTable2 rendering
  βœ… renders item values after compute completes
  βœ… shows CircularProgressIndicator while loading
  βœ… renders without errors when items is empty
ThemedTable2 column key collision regression
  βœ… two columns with identical headerText show distinct data
ThemedTable2 search
  βœ… filters items matching the query
  βœ… search matches values from all columns
  βœ… shows all items when search is cleared
ThemedTable2 sort
  βœ… controller.sort ascending orders items Aβ†’Z
  βœ… controller.sort descending orders items Zβ†’A
  βœ… numeric values sort as numbers not as strings
  βœ… controller.refresh re-runs sort without changing order
ThemedTable2 didUpdateWidget
  βœ… reflects new items when widget rebuilds with a different list
  βœ… handles growing list without losing existing rows
  βœ… detects edit in middle of same-length list (DeepCollectionEquality regression)

βœ…Β test/widgets/tabs_test.dart

ThemedTabView widget
  βœ… renders with multiple tabs
  βœ… displays initial tab content
  βœ… switches tabs on tap
  βœ… calls onTabIndex callback when tab changes
  βœ… renders arrow buttons when showArrows is true
  βœ… arrow buttons exist and are functional
  βœ… left arrow is disabled on first tab
  βœ… right arrow is disabled on last tab
  βœ… handles initialPosition correctly
  βœ… clamps invalid initialPosition to valid range
  βœ… persists tab position on widget rebuild
  βœ… resets tab position when tabs list changes and persistTabPosition is false
  βœ… renders additionalWidgets
  βœ… renders with different tab styles
  βœ… ThemedTab renders with leading icon
  βœ… ThemedTab renders with trailing icon
  βœ… renders with custom padding and alignment
  βœ… arrow button state updates when navigating between tabs (bug regression)
  βœ… wrapArrowNavigation wraps from last tab to first tab
  βœ… wrapArrowNavigation wraps from first tab to last tab
  βœ… wrapArrowNavigation keeps arrows enabled at boundaries