Skip to content

Releases: jwstegemann/fritz2

Version 0.8

03 Dec 18:27
Compare
Choose a tag to compare

breaking changes

This release contains changes that break code written with earlier versions. Hopefully these are the last major api-changes prior to fritz2 1.0:

Setting attributes per function

In fritz2 0.8 we decided to use functions to set attribute values instead of vars with delegation.
That way you do not have to wrap constant values in a Flow anymore. This yields better performance and the const()-function could be removed. For convenience reasons we also added a new function asString for Flows to
convert a Flow to a Flow<String> by calling the toString() method internally.

input {
    type("text") // native
    value(myStore.data) // flow
    name(otherStore.data.asString()) // otherStore.data is not a Flow of String
}

RenderContext replaces HtmlElements

We renamed the HtmlElements interface to RenderContext, because we think this name better fits the Kotlin DSL approach.
The idea behind it is that every render function creates a new RenderContext in which
new Tags can be created. This also means that you must replace the receiver type in your custom component-functions accordingly:

val errorStore = storeOf("some text")

// own component
fun RenderContext.errorText(text: String): P {
    return p("error") {
        +text
    }
}

errorStore.data.render { //this: RenderContext
    errorText(it)
}

Adding Text and Comments

We clarified the creation of TextNodes in Tags. Now you use unary +-operator for constant Strings
to append text at this position to your Tag. If you have a Flow, call asText() instead.
To create a CommentNode, you can use the !-operator and asComment() analogous. This intentionally follows a different approach in contrast to the attribute functions so it can be distinguished more easily.

p {
    +"Hello "
    myStore.data.asText()

    !"this is a comment"
    myStore.data.asComment()
}

Evolution of render() and renderEach()

Using former fritz2-versions you mapped a Flow of data to a Flow of Tags and created a MountPoint explicitly by calling bind() at some place in your rendering. This was error prone. Since nobody would do anything with a Flow<Tag> other than binding it, all render functions now implicitly create the mount point and therefore no bind() is necessary anymore. It has been removed completely.

val myStore = storeOf(listOf("a","b","c"))

render {
    ul {
    	myStore.data.renderEach {
    		li { +it }
    	} // no .bind() here anymore
    }
}

For performance reasons the render-functions prior to version 0.8 did not allow more than one root-element. In version 0.8 the standard render allows you to add as many root elements to your context as you want or even none:

val myStore = storeOf(42)

// renders multiple root-elements
myStore.data.render {
	repeat(it) {
		div { +"one more" }
	}
}

// does only render something if value is large enough
myStore.data.render {
	if (it > 100) {
		div { +"number" }
	}
}

If you you do not need this feature (because you know you will always have exactly one root-element) use renderElement() instead to get (slightly) improved performance.

render() and renderElement() now reserve their place in the DOM until the content is rendered by using a temporary placeholder. Since this costs some performance you can disable it when you are sure that there are no sibling-elements on the same level in your DOM-tree by setting renderElement(preserveOrder = false). Use this when you have to render lots of elements (in huge lists, tables, etc.).

Instead of someListFlow.each().render {...}.bind() you now simply write someListFlow.renderEach {...}. This is analog for all flavors of renderEach on Stores and Flows with and without an idProvider.
Please note that renderEach() still allows only one root-element (like renderElement)!

Tracker offers Flow<Boolean>

Tracker now implements Flow<Boolean> instead of Flow<String?>so it adopts better to most use-cases. Find an example here.

new features

improvements

  • update all dependencies to latest version PR#166
  • extend Router functionality PR#197
  • upgraded Dokka-version and moved to html for api-docs PR#194
  • annotation processor visibility option PR#178
  • use local test server PR#165

fixed bugs

  • fix memory leaks and performance issues PR#180 PR#185
  • no trailing slash in remote PR#167
  • fix boolean attribute delegates PR#172

Version 0.7.2

15 Oct 09:29
Compare
Choose a tag to compare

Small patch resolving a memory issue related to coroutine scopes.

Version 0.7.1

06 Sep 19:37
Compare
Choose a tag to compare

Just a small patch to be compatible with Kotlin 1.4.0.

No new features or bug fixes included.

Version 0.7

13 Aug 21:39
Compare
Choose a tag to compare

breaking changes

This release contains changes that break code written with earlier versions:

  • Handlers are now suspendable, so you can call suspend-methods directly inside your Handler. There is no need for Applicator anymore. Therefore this class and its utility-functions have been removed. (PR#124 & PR#126)
  • FormateStore and interface Format have been removed. Use format-factory-function inside lenses package to create a formatting Lens and create a normal SubStore (by using sub). (PR#139 & PR#146)
val df: DateFormat = DateFormat("yyyy-MM-dd")
// converts a Date into String in vice versa
val dateFormat = format(
    parse = { df.parseDate(it) },
    format = { df.format(it) }
)

//using the dateLens
val birthday = personStore.sub(L.Person.birthday + dateFormat)
// or
val birthday = personStore.sub(L.Person.birthday).sub(dateFormat)
  • Validation has been extracted as a service and refactored to be more concise. (PR#149 & #157)

in commonMain

data class Message(val id: String, val status: Status, val text: String) : ValidationMessage {
    override fun isError(): Boolean = status > Status.Valid // renamed from failed() -> isError()
}

object PersonValidator : Validator<Person, Message, String>() {
   // return your validation messages here
   override fun validate(data: Person, metadata: String): List<Message> {
       ...
   }
}

in jsMain

val personStore = object : RootStore<Person>(Person()) {    
    // only update when it's valid
    val addOrUpdate = handle<Person> { oldPerson, newPerson ->
        if (PersonValidator.isValid(newPerson, "update")) new else oldPerson
    }
}
...

// then render the validation message list in your html
PersonValidator.msgs.render { msg ->
    ...
}.bind()

in jvmMain

if (PersonValidator.isValid(newPerson , "add")) {
    //e.g. save your new Person to Database
    ...
} else {
   // get the messages, only available after isValid() was called
   val msgs = PersonValidator.msgs
   ...
}

new features

  • added tracking-service to access process state of Handlers (e.g. to show process indicator). (PR#147)
  • added history-service to keep track of historical values in Stores and provide back() function. (PR#152)
  • added Repository to offer CRUD-functionality for entities and dealing with queries. Implementations are available for REST and LocalStorage (see example). (PR#141, PR#144, PR#155 & PR#153)
  • added storeOf() function to create a minimal RootStore (without Handlers) (PR#144)
  • added convenience-function render on Seq, so you can directly write each(...).render { ... } (and leave out map) (PR#142)
  • added convenience-function render on Flow, so you can directly write flow.render { ... } (and leave out map) (PR#154)
  • added functions to deal with errors in Handlers (PR#137)
  • snapshots are now provided on oss.jfrog.org (PR#128)
  • added append function to remote (PR#127)
  • changed IdProvider to generic type (PR#123)
  • use Inspector (created by inspect()-function) to navigate through your model in validation and test and have data and corresponding ids available at any point (PR#118)

fixed bugs

  • added isValid on JVM (PR#135)
  • added missing factories for <dt> and <dd> (PR#134)
  • added missing SelectedAttributeDelegate (PR#131)
  • fixed some bugs in Router and minor API changes (PR#151)

Version 0.6

13 Jul 11:40
Compare
Choose a tag to compare

breaking changes

This release contains changes that break code written with earlier versions:

  • You no longer need to inherit WithId in your model-classes (the interface has been removed from fritz2 entirely). Instead, you need to provide a function which returns the id of a certain instance. This function can be used when calling each or creating a SubStore for a certain element (PR#94):
// in commonMain
@Lenses
data class Model(val id: String, val value: String)

// in jsMain
val store = RootStore<List<Model>>(listOf(...))

render {
  ul {
    store.each(Model::id).map { modelStore ->
      render {
        li { modelStore.sub(L.Model.value).data.bind() }
      }
    }.bind()
  }
}.mount("target")
  • All of the each methods (PR#113) were unified:

    • use Flow<T>.each() to map each instance of T to your Tags. It uses Kotlin's equality function to determine whether or not two elements are the same, and therefore re-renders the whole content you mapped when an element is changed or moved.

    • with Flow<T>.each(idProvider: (T) -> String) you can also map each instance of T to your Tags, but it uses the given idProvider to determine whether or not two elements are the same. In your mapping, you can get a SubStore for an element using listStore.sub(id, idProvider), so only the parts that actually changed will be re-rendered.

    • use Store<List<T>>.each() to map a SubStore<T> to Tags. It uses the list position of the element to determine whether or not two elements are the same. This means that when inserting something into the middle of the list, the changed element AND ALL following elements will be re-rendered.

    • with Store<List<T>>.each(idProvider: (T) -> String) you can also map a SubStore<T> to Tags, but it uses the given idProvider to determine whether or not two elements are the same`, so only the parts that actually changed will be re-rendered.

    • renamed handleAndEmit to handleAndOffer (PR#109)

    • renamed ModelIdRoot to RootModelId to follow the naming of stores (PR#96)

new features

  • add static text in HTML by +"yourText" (PR#95)
  • add HTML-comments by comment("yourText") or !"yourText" (PR#108)
  • use the action function to dispatch an action at any point in your code (PR#117)

fixed bugs

  • fixed handling of value and checked attributes (PR#81)
  • fixed MapRouter to use Map<String,String> (PR#82)
  • fixed double kotlin-block in gradle build-file (PR#97)
  • ensure order of children when mixing static tags with bound values on the same level by using bind(preserveOrder = true) (PR#102)
  • classes of HTML-tags are now open so you can inherit your own tags from them (PR#104)
  • SingleMountPoint for Boolean (leaving out the attribute if false) (PR#105)

Version 0.5

11 Jun 14:27
0e77587
Compare
Choose a tag to compare

breaking changes

This release contains changes, that break code written with earlier versions:

  • We moved all artifacts and packages to match our domain: dev.fritz2. You will have to adjust your inputs and dependencies accordingly.
  • The default project-type for fritz2 now is multiplatform (to make it easy to share models and validation between client and server). Use the new fritz2-gradle-plugin to setup your project:

build.gradle.kts

plugins {
    id("dev.fritz2.fritz2-gradle") version "0.5"
}

repositories {
    jcenter()
}

kotlin {
    kotlin {
        jvm()
        js().browser()

        sourceSets {
            val commonMain by getting {
                dependencies {
                    implementation(kotlin("stdlib"))
                }
            }
            val jvmMain by getting {
                dependencies {
                }
            }
            val jsMain by getting {
                dependencies {
                }
            }
        }
    }
}

fixed bugs

  • fixed dom-update problem with checked attribute at HTMLInputElement

Version 0.4

26 May 20:35
391d73d
Compare
Choose a tag to compare

breaking changes

This release contains changes, that break code written with earlier versions:

  • since it was the source of much confusion we renamed the function to build a tree of Tags (formerly html) to render:
render {
    div("my-class") {
        // ...
    }
}
  • the overloaded operator <= to bind a Flow of actions or events to a Handler was definitely not Kotlin-like, so we replaced it by the handledBy infix-function (please note the reversed order):
button("btn btn-primary") {
    text("Add a dot")
    clicks handledBy store.addADot
}

new features

  • improved remote-api
  • support for building and using WebComponents

bug fixes

  • improved examples
  • improved documentation

build.gradle.kts

Kotlin style

dependencies {
    implementation("io.fritz2:fritz2-core-js:0.4")
}

Groovy style

dependencies {
    implementation 'io.fritz2:fritz2-core-js:0.4'
}

Version 0.3

22 Apr 19:20
Compare
Choose a tag to compare
  • several bug-fixes
  • tidyed up syntax for text, attr, const
  • better examples
  • Improved diff-algorithm for list-handling
  • better extractions on events (current value, selected item, etc.)
  • reworked structure of GitHub-projects

Version 0.2

19 Mar 20:26
61f8665
Compare
Choose a tag to compare

First automated release using github actions...

Version 0.1

28 Feb 20:53
Compare
Choose a tag to compare
Version 0.1 Pre-release
Pre-release

Our first public release, just to test the build- and publish-process.