Skip to content

Commit d9d4bf3

Browse files
authoredJan 31, 2024
Add opportunity to use custom prefixes in StyleSheet (JetBrains#3015)
1 parent b1e86ad commit d9d4bf3

File tree

3 files changed

+99
-9
lines changed

3 files changed

+99
-9
lines changed
 

‎html/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/StyleSheet.kt

+20-9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ class CSSRulesHolderState : CSSRulesHolder {
2020
/**
2121
* Represents a collection of the css style rules.
2222
* StyleSheet needs to be mounted.
23+
*
24+
* @param customPrefix Will be used as prefix with current style. Pass `null` to use default value (classname of realization)
25+
*
2326
* @see [Style]
2427
*
2528
* Example:
@@ -38,12 +41,22 @@ class CSSRulesHolderState : CSSRulesHolder {
3841
* ```
3942
*/
4043
open class StyleSheet(
44+
customPrefix: String?,
4145
private val rulesHolder: CSSRulesHolder = CSSRulesHolderState(),
42-
val usePrefix: Boolean = true,
4346
) : StyleSheetBuilder, CSSRulesHolder by rulesHolder {
4447
private val boundClasses = mutableMapOf<String, CSSRuleDeclarationList>()
48+
protected val prefix: String = customPrefix ?: "${this::class.simpleName}-"
49+
50+
val usePrefix: Boolean = customPrefix == null
51+
constructor(
52+
rulesHolder: CSSRulesHolder = CSSRulesHolderState(),
53+
usePrefix: Boolean = true
54+
) : this(
55+
if (usePrefix) null else "",
56+
rulesHolder
57+
)
4558

46-
protected fun style(cssRule: CSSBuilder.() -> Unit) = CSSHolder(usePrefix, cssRule)
59+
protected fun style(cssRule: CSSBuilder.() -> Unit) = CSSHolder(prefix, cssRule)
4760

4861
/**
4962
* Example:
@@ -69,7 +82,7 @@ open class StyleSheet(
6982
* }
7083
* ```
7184
*/
72-
protected fun keyframes(cssKeyframes: CSSKeyframesBuilder.() -> Unit) = CSSKeyframesHolder(usePrefix, cssKeyframes)
85+
protected fun keyframes(cssKeyframes: CSSKeyframesBuilder.() -> Unit) = CSSKeyframesHolder(prefix, cssKeyframes)
7386

7487
companion object {
7588
private var counter = 0
@@ -88,13 +101,12 @@ open class StyleSheet(
88101
}
89102
}
90103

91-
protected class CSSHolder(private val usePrefix: Boolean, private val cssBuilder: CSSBuilder.() -> Unit) {
104+
protected class CSSHolder(private val prefix: String, private val cssBuilder: CSSBuilder.() -> Unit) {
92105
operator fun provideDelegate(
93106
sheet: StyleSheet,
94107
property: KProperty<*>
95108
): ReadOnlyProperty<Any?, String> {
96-
val sheetName = if (usePrefix) "${sheet::class.simpleName}-" else ""
97-
val className = "$sheetName${property.name}"
109+
val className = "$prefix${property.name}"
98110
val selector = object : CSSSelector() {
99111
override fun asString() = ".${className}"
100112
}
@@ -110,15 +122,14 @@ open class StyleSheet(
110122
* See [keyframes]
111123
*/
112124
protected class CSSKeyframesHolder(
113-
private val usePrefix: Boolean,
125+
private val prefix: String,
114126
private val keyframesBuilder: CSSKeyframesBuilder.() -> Unit
115127
) {
116128
operator fun provideDelegate(
117129
sheet: StyleSheet,
118130
property: KProperty<*>
119131
): ReadOnlyProperty<Any?, CSSNamedKeyframes> {
120-
val sheetName = if (usePrefix) "${sheet::class.simpleName}-" else ""
121-
val keyframesName = "$sheetName${property.name}"
132+
val keyframesName = "$prefix${property.name}"
122133
val rule = buildKeyframes(keyframesName, keyframesBuilder)
123134
sheet.add(rule)
124135

‎html/core/src/jsTest/kotlin/css/AnimationTests.kt

+49
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,28 @@ object AnimationsStyleSheet : StyleSheet() {
3535
}
3636
}
3737

38+
class AnimationsStyleSheetWithCustomPrefix(
39+
customPrefix: String
40+
) : StyleSheet(customPrefix) {
41+
val bounce by keyframes {
42+
from {
43+
property("transform", "translateX(50%)")
44+
}
45+
46+
to {
47+
property("transform", "translateX(-50%)")
48+
}
49+
}
50+
51+
val animationClass by style {
52+
animation(bounce) {
53+
duration(2.s)
54+
timingFunction(AnimationTimingFunction.EaseIn)
55+
direction(AnimationDirection.Alternate)
56+
}
57+
}
58+
}
59+
3860
@ExperimentalComposeWebApi
3961
class AnimationTests {
4062
@Test
@@ -76,4 +98,31 @@ class AnimationTests {
7698
"Animation class wasn't injected correctly"
7799
)
78100
}
101+
102+
@Test
103+
fun animationClassInjectedWithCustomPrefix() = runTest {
104+
val customPrefix = "CustomPrefix-"
105+
composition {
106+
Style(AnimationsStyleSheetWithCustomPrefix(customPrefix))
107+
}
108+
109+
val el = nextChild() as HTMLStyleElement
110+
val cssRules = (el.sheet as? CSSStyleSheet)?.cssRules
111+
val rules = (0 until (cssRules?.length ?: 0)).map {
112+
cssRules?.item(it)?.cssText?.replace("\n", "") ?: ""
113+
}
114+
115+
// TODO: we need to come up with test that not relying on any kind of formatting
116+
assertEquals(
117+
"@keyframes ${customPrefix}bounce {0% { transform: translateX(50%); }100% { transform: translateX(-50%); }}",
118+
rules[0].replace(" 0%", "0%").replace(" 100%", "100%"),
119+
"Animation keyframes wasn't injected correctly"
120+
)
121+
122+
assertEquals(
123+
".${customPrefix}animationClass { animation: 2s ease-in 0s 1 alternate none running ${customPrefix}bounce; }".trimIndent(),
124+
rules[1],
125+
"Animation class wasn't injected correctly"
126+
)
127+
}
79128
}

‎html/core/src/jsTest/kotlin/css/StyleSheetTests.kt

+30
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,34 @@ class StyleSheetTests {
4242
)
4343
}
4444

45+
@Test
46+
fun stylesheetCorrectlyUsingIncomingPrefix() {
47+
val testPrefixParent = "test_prefix_parent-"
48+
val testPrefixChild = "test_prefix_child-"
49+
50+
val styleSheet = object : StyleSheet(customPrefix = testPrefixParent) {
51+
val someClassName by style {
52+
color(Color.red)
53+
}
54+
}
55+
56+
val childStyleSheet = object : StyleSheet(customPrefix = testPrefixChild, styleSheet) {
57+
val someClassName by style {
58+
color(Color.green)
59+
}
60+
}
61+
62+
assertContentEquals(
63+
listOf(".${testPrefixParent}someClassName { color: red;}", ".${testPrefixChild}someClassName { color: green;}"),
64+
styleSheet.serializeRules(),
65+
"styleSheet rules"
66+
)
67+
68+
assertContentEquals(
69+
listOf(".${testPrefixParent}someClassName { color: red;}", ".${testPrefixChild}someClassName { color: green;}"),
70+
childStyleSheet.serializeRules(),
71+
"childStyleSheet rules"
72+
)
73+
}
74+
4575
}

0 commit comments

Comments
 (0)
Please sign in to comment.