Coverage for fastblocks/adapters/icons/_utils.py: 0%

49 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-10-09 00:47 -0700

1"""Shared utilities for icon adapters to reduce complexity.""" 

2 

3from typing import Any 

4 

5 

6def process_size_attribute( 

7 size: str | None, 

8 size_presets: dict[str, str], 

9 prefix: str, 

10 attributes: dict[str, Any], 

11) -> tuple[str, dict[str, Any]]: 

12 """Process size attribute and return class additions.""" 

13 if not size: 

14 return "", attributes 

15 

16 if size in size_presets: 

17 return f" {prefix}-{size}", attributes 

18 

19 # Custom size via style 

20 style = attributes.get("style", "") 

21 attributes["style"] = f"font-size: {size}; {style}" 

22 return "", attributes 

23 

24 

25def process_transformations( 

26 attributes: dict[str, Any], prefix: str 

27) -> tuple[str, dict[str, Any]]: 

28 """Process rotation and flip transformations.""" 

29 classes = [] 

30 

31 if "rotate" in attributes: 

32 rotation = attributes.pop("rotate") 

33 if rotation in ("90", "180", "270"): 

34 classes.append(f"{prefix}-rotate-{rotation}") 

35 

36 if "flip" in attributes: 

37 flip = attributes.pop("flip") 

38 if flip in ("horizontal", "vertical"): 

39 classes.append(f"{prefix}-flip-{flip}") 

40 

41 return " ".join(f" {c}" for c in classes), attributes 

42 

43 

44def process_animations( 

45 attributes: dict[str, Any], animation_types: list[str], prefix: str 

46) -> tuple[str, dict[str, Any]]: 

47 """Process animation attributes.""" 

48 classes = [ 

49 f"{prefix}-{animation}" 

50 for animation in animation_types 

51 if animation in attributes and attributes.pop(animation) 

52 ] 

53 

54 return " ".join(f" {c}" for c in classes), attributes 

55 

56 

57def process_semantic_colors( 

58 attributes: dict[str, Any], 

59 semantic_colors: list[str], 

60 prefix: str, 

61) -> tuple[str, dict[str, Any]]: 

62 """Process semantic color attributes.""" 

63 if "color" not in attributes: 

64 return "", attributes 

65 

66 color = attributes.pop("color") 

67 

68 if color in semantic_colors: 

69 return f" {prefix}-{color}", attributes 

70 

71 # Custom color via style 

72 style = attributes.get("style", "") 

73 attributes["style"] = f"color: {color}; {style}" 

74 return "", attributes 

75 

76 

77def process_state_attributes( 

78 attributes: dict[str, Any], prefix: str 

79) -> tuple[str, dict[str, Any]]: 

80 """Process interactive and state attributes.""" 

81 classes = [] 

82 

83 if "interactive" in attributes and attributes.pop("interactive"): 

84 classes.append(f"{prefix}-interactive") 

85 

86 if "disabled" in attributes and attributes.pop("disabled"): 

87 classes.append(f"{prefix}-disabled") 

88 

89 if "loading" in attributes and attributes.pop("loading"): 

90 classes.append(f"{prefix}-loading") 

91 

92 if "inactive" in attributes and attributes.pop("inactive"): 

93 classes.append(f"{prefix}-inactive") 

94 

95 return " ".join(f" {c}" for c in classes), attributes 

96 

97 

98def add_accessibility_attributes(attributes: dict[str, Any]) -> dict[str, Any]: 

99 """Add default accessibility attributes if missing.""" 

100 if "aria-label" not in attributes and "title" not in attributes: 

101 attributes["aria-hidden"] = "true" 

102 return attributes 

103 

104 

105def build_attr_string(attributes: dict[str, Any]) -> str: 

106 """Build HTML attribute string from dict.""" 

107 return " ".join(f'{k}="{v}"' for k, v in attributes.items() if v is not None)