Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename classes utility function to joinClasses in order to reduce naming confusion #859

Merged
merged 4 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions core/src/jsMain/kotlin/dev/fritz2/core/foundation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,39 @@ fun addGlobalStyles(css: List<String>) {
* Joins all given [classes] strings to one html-class-attribute [String]
* by filtering all out which are null or blank.
*/
fun classes(vararg classes: String?): String =
classes.filter { !it.isNullOrBlank() }.joinToString(" ")
@Deprecated("Use joinClassNames instead.", ReplaceWith("joinClasses(*classes)"))
fun classes(vararg classes: String?): String = joinClasses(*classes)

/**
* Joins all given [classes] strings to one html-class-attribute [String].
* Individual Strings that are null or blank are filtered out.
*
* __Examples__
*
* ```
* val classes = joinClasses(
* "class1",
* null,
* "class2",
* ""
* )
* println(classes) // prints "class1 class2"
* ```
*
* Using this function, it is also possible to conditionally construct classes strings without having
* to do dangerous string concatenation:
*
* ```
* val classes = joinClasses(
* "class1",
* "class2".takeIf { it.length > 10 }
* )
*
* println(classes) // prints "class1"
* ```
*/
fun joinClasses(vararg classes: String?): String =
classes.filterNot(String?::isNullOrBlank).joinToString(separator = " ")

/**
* Helper function to call a native js function with concrete return type [T]
Expand Down
6 changes: 4 additions & 2 deletions core/src/jsMain/kotlin/dev/fritz2/core/tags.kt
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,9 @@ open class HtmlTag<out E : Element>(
private val classesStateFlow by lazy {
MutableStateFlow<List<StateFlow<String>>>(listOfNotNull(baseClass?.let { MutableStateFlow(it) }))
.also { classesFlowList ->
attr("class", classesFlowList.flatMapLatest { styleFlows -> combine(styleFlows) { classes(*it) } })
attr("class", classesFlowList.flatMapLatest { styleFlows ->
combine(styleFlows) { joinClasses(*it) }
})
}
}

Expand All @@ -386,7 +388,7 @@ open class HtmlTag<out E : Element>(
* This function is used to create the initial class name values to be applied immediately
* to the domnode.
*/
private fun buildClasses() = classes(*classesStateFlow.value.map { it.value }.toTypedArray())
private fun buildClasses() = joinClasses(*classesStateFlow.value.map { it.value }.toTypedArray())

override fun className(value: String) {
classesStateFlow.value += MutableStateFlow(value)
Expand Down
10 changes: 5 additions & 5 deletions core/src/jsMain/kotlin/dev/fritz2/core/transitions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ class Transition(
val transition = payload.unsafeCast<Transition?>()
if (transition?.enter != null) {
val classes = target.domNode.getAttribute("class").orEmpty()
target.domNode.setAttribute("class", classes(classes, transition.enterStart))
target.domNode.setAttribute("class", joinClasses(classes, transition.enterStart))
kotlinx.browser.window.awaitAnimationFrame()
kotlinx.browser.window.awaitAnimationFrame()
target.domNode.setAttribute(
"class",
classes(classes, transition.enter, transition.enterEnd)
joinClasses(classes, transition.enter, transition.enterEnd)
)
target.waitForAnimation()
target.domNode.setAttribute("class", classes)
Expand Down Expand Up @@ -144,14 +144,14 @@ fun Tag<HTMLElement>.transition(on: Flow<Boolean>, transition: Transition) {
emit(transition.enterStart.orEmpty())
kotlinx.browser.window.awaitAnimationFrame()
kotlinx.browser.window.awaitAnimationFrame()
emit(classes(transition.enter, transition.enterEnd))
emit(joinClasses(transition.enter, transition.enterEnd))
waitForAnimation()
emit("")
} else {
emit(classes(transition.leaveStart))
emit(joinClasses(transition.leaveStart))
kotlinx.browser.window.awaitAnimationFrame()
kotlinx.browser.window.awaitAnimationFrame()
emit(classes(transition.leave, transition.leaveEnd))
emit(joinClasses(transition.leave, transition.leaveEnd))
waitForAnimation()
emit("")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ fun main() {
div("row") {
gameStore.field.renderEach { cell ->
div(
classes(
joinClasses(
"col-4 border d-flex justify-content-center align-items-center",
if (cell.isInWinningGroup) "bg-success" else "bg-white"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ fun RenderContext.gridListDemo(amount: Int) {
tag = RenderContext::li
) {
className(selected.combine(active) { sel, act ->
classes(
joinClasses(
if (act) "ring-4 ring-primary-600" else "",
if (sel) "bg-primary-700 text-primary-100" else "bg-primary-200 text-primary-900"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ fun RenderContext.inputFieldDemo() {
| disabled:opacity-50""".trimMargin()
) {
className(value.hasError.map {
if (it) classes(
if (it) joinClasses(
"""border border-error-600
| text-error-800 placeholder:text-error-400
| hover:border-error-800
| focus:outline-none focus:ring-4 focus:ring-error-600 focus:border-error-800""".trimMargin()
)
else classes(
else joinClasses(
"""border border-primary-600
| text-primary-800 placeholder:text-slate-400
| hover:border-primary-800
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package dev.fritz2.headlessdemo.components

import dev.fritz2.core.RenderContext
import dev.fritz2.core.classes
import dev.fritz2.core.joinClasses
import dev.fritz2.core.placeholder
import dev.fritz2.core.storeOf
import dev.fritz2.headless.components.textArea
Expand All @@ -28,13 +28,13 @@ fun RenderContext.textAreaDemo() {
| disabled:opacity-50""".trimMargin()
) {
className(value.hasError.map {
if (it) classes(
if (it) joinClasses(
"""border border-error-600
| text-error-800 placeholder:text-error-400
| hover:border-error-800
| focus:outline-none focus:ring-4 focus:ring-error-600 focus:border-error-800""".trimMargin()
)
else classes(
else joinClasses(
"""border border-primary-600
| text-primary-800 placeholder:text-slate-400
| hover:border-primary-800
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ class DataCollection<T, C : HTMLElement>(tag: Tag<C>) : Tag<C> by tag {

return tag(
this,
if (selection.isSet) classes(classes, "cursor-pointer") else classes,
if (selection.isSet) joinClasses(classes, "cursor-pointer") else classes,
itemId,
scope
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ fun <T, C : HTMLElement> RenderContext.listbox(
initialize: Listbox<T, C>.() -> Unit
): Tag<C> {
addComponentStructureInfo(Listbox.COMPONENT_NAME, [email protected], this)
return tag(this, classes(classes, "relative"), id, scope) {
return tag(this, joinClasses(classes, "relative"), id, scope) {
Listbox<T, C>(this, id).run {
initialize(this)
render()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ fun <C : HTMLElement> RenderContext.menu(
initialize: Menu<C>.() -> Unit
): Tag<C> {
addComponentStructureInfo("menu", [email protected], this)
return tag(this, classes(classes, "relative"), id, scope) {
return tag(this, joinClasses(classes, "relative"), id, scope) {
Menu(this, id).run {
initialize(this)
render()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ fun <C : HTMLElement> RenderContext.popOver(
initialize: PopOver<C>.() -> Unit
): Tag<C> {
addComponentStructureInfo("popOver", [email protected], this)
return tag(this, classes(classes, PopUpPanel.POPUP_RELATIVE), id, scope) {
return tag(this, joinClasses(classes, PopUpPanel.POPUP_RELATIVE), id, scope) {
PopOver(this, id).run {
initialize(this)
render()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ abstract class PopUpPanel<C : HTMLElement>(
* @param offset the distance between the reference element and the panel in pixels. Defaults to `5`
*/
fun arrow(size: String = "popup-arrow-default", offset: Int = 5) {
div(classes(size, "popup-arrow")) {
div(joinClasses(size, "popup-arrow")) {
arrow = this
addMiddleware(offset(offset))
addMiddleware(arrow { element = domNode })
Expand Down
4 changes: 2 additions & 2 deletions www/src/pages/headless/radioGroup.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ radioGroup<HTMLFieldSetElement, Plan?>(tag = RenderContext::fieldset) {
radioGroupOptionToggle {
// combine `selected` and `active`-Flow with `className` to react to state changes
className(selected.combine(active) { sel, act ->
// use `classes` to attach both styling results
classes(
// use `joinClasses` to attach both styling results
joinClasses(
if (sel) "bg-indigo-200" else "bg-white",
if (act) "ring-2 ring-indigo-500 border-transparent" else "border-gray-300"
)
Expand Down
4 changes: 2 additions & 2 deletions www/src/pages/headless/tabGroup.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ tabGroup {
tab {
// combine `selected` and `active`-Flow with `className` to react to state changes
className(selected.combine(active) { sel, act ->
// use `classes` to attach both styling results
classes(
// use `joinClasses` to attach both styling results
joinClasses(
if (sel == index) "bg-primary-800 text-white shadow-md"
else "text-primary-100 hover:bg-primary-900/[0.12]",
if (act) "ring-2 ring-white border-transparent"
Expand Down
2 changes: 1 addition & 1 deletion www/src/pages/headless/toast.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ toast("default") {

button {
icon(
classes = "w-4 h-4 text-primary-900",
joinClasses = "w-4 h-4 text-primary-900",
content = HeroIcons.x
)
clicks handledBy close // call close handler
Expand Down
Loading