diff --git a/styles/constants.go b/styles/constants.go index 63841bc..c7d3d02 100644 --- a/styles/constants.go +++ b/styles/constants.go @@ -212,4 +212,8 @@ const ( // Animations pseudo-classes PseudoPlaying = ":playing" PseudoPaused = ":paused" + + // Content pseudo-elements + PseudoBefore = "::before" + PseudoAfter = "::after" ) diff --git a/styles/stylemanager.go b/styles/stylemanager.go index a9e31c7..d729f8a 100644 --- a/styles/stylemanager.go +++ b/styles/stylemanager.go @@ -14,6 +14,7 @@ type Keyframes map[string]Props type CompositeStyle struct { Default Props PseudoClasses map[string]Props + PseudoElements map[string]Props MediaQueries map[string]Props } @@ -123,6 +124,17 @@ func (sm *StyleManager) GenerateCSS() string { builder.WriteString("} ") } + for pseudoElement, style := range composite.PseudoElements { + // Ensure pseudoElement starts with a double colon + formattedPseudoElement := fmt.Sprintf("%s%s", className, ensureDoubleLeadingColon(pseudoElement)) + keys := sortedKeys(style) + builder.WriteString(fmt.Sprintf(".%s { ", formattedPseudoElement)) + for _, prop := range keys { + builder.WriteString(fmt.Sprintf("%s: %s; ", prop, style[prop])) + } + builder.WriteString("} ") + } + for mediaQuery, style := range composite.MediaQueries { // Ensure mediaQuery is correctly prefixed formattedMediaQuery := ensureMediaPrefix(mediaQuery) @@ -146,6 +158,14 @@ func ensureLeadingColon(pseudoClass string) string { return ":" + pseudoClass } +// ensureDoubleLeadingColon ensures that the pseudoElement starts with a double colon. +func ensureDoubleLeadingColon(pseudoElement string) string { + if strings.HasPrefix(pseudoElement, "::") { + return pseudoElement + } + return "::" + pseudoElement +} + // ensureMediaPrefix ensures that the mediaQuery starts with "@media". func ensureMediaPrefix(mediaQuery string) string { if !strings.HasPrefix(mediaQuery, "@media") { diff --git a/styles/stylemanager_test.go b/styles/stylemanager_test.go index ba6c070..7f50c9d 100644 --- a/styles/stylemanager_test.go +++ b/styles/stylemanager_test.go @@ -105,6 +105,9 @@ func TestGenerateCSS(t *testing.T) { PseudoClasses: map[string]Props{ "hover": Props{"color": "blue"}, }, + PseudoElements: map[string]Props{ + "before": Props{"content": "'[x] '"}, + }, MediaQueries: map[string]Props{ "@media (min-width: 768px)": Props{"color": "green", "background": "yellow"}, "@media (min-width: 1024px)": Props{"color": "purple", "background": "orange"}, @@ -128,6 +131,9 @@ func TestGenerateCSS(t *testing.T) { assert.Contains(t, css, fmt.Sprintf(".%s { color: pink; }", compositeClassName), "CSS should contain the composite default") assert.Contains(t, css, fmt.Sprintf(".%s:hover { color: blue; }", compositeClassName), "CSS should contain the composite hover") + // Assertion for the usage of pseudo elements. + assert.Contains(t, css, fmt.Sprintf(".%s::before { content: '[x] '; }", compositeClassName), "CSS should contain the composite before") + // Assertions for media queries. assert.Contains(t, css, fmt.Sprintf("@media (min-width: 768px) { .%s { background: yellow; color: green; } }", compositeClassName), "CSS should contain the first media query") assert.Contains(t, css, fmt.Sprintf("@media (min-width: 1024px) { .%s { background: orange; color: purple; } }", compositeClassName), "CSS should contain the second media query")