feat(claude-plugin): restructure skills and add themed-button, themed-alert, themed-snackbar; fix ThemedColorPicker bugs #133
GitHub Actions / Unit Tests
succeeded
Apr 22, 2026 in 1s
402 passed, 0 failed and 0 skipped
β Β 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
Loading