All Versions
10
Latest Version
0.8
Avg Release Cycle
31 days
Latest Release
316 days ago

Changelog History

  • v0.8 Changes

    December 03, 2020

    ๐Ÿ’ฅ 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 componentfun 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-elementsmyStore.data.render { repeat(it) { div { +"one more" } } }// does only render something if value is large enoughmyStore.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

    • ๐Ÿ‘ Websocket support PR#175
    • Styling and Components PR#176

    ๐Ÿ‘Œ 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
  • v0.7.2 Changes

    October 15, 2020

    Small patch resolving a memory issue related to coroutine scopes.

  • v0.7.1 Changes

    September 06, 2020

    ๐Ÿ“„ Just a small patch to be compatible with Kotlin 1.4.0.

    ๐Ÿ›  No new, features or bug fixes included.

  • v0.7 Changes

    August 13, 2020

    ๐Ÿ’ฅ 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 it's 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 versaval dateFormat = format( parse = { df.parseDate(it) }, format = { df.format(it) } )//using the dateLensval birthday = personStore.sub(L.Person.birthday + dateFormat)// orval 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 hereoverride fun validate(data: Person, metadata: String): List\<Message\> { ... } }
    

    in jsMain

    val personStore = object : RootStore\<Person\>(Person()) { // only update when it's validval addOrUpdate = handle\<Person\> { oldPerson, newPerson -\>if (PersonValidator.isValid(newPerson, "update")) new else oldPerson } } ...// then render the validation message list in your htmlPersonValidator.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 calledval 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-funtion render on Seq, so you can directly write each(...).render { ... } (and leave out map) (PR#142)
    • โž• added convenience-funtion 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 SelectedAttribteDelegate (PR#131)
    • ๐Ÿ›  fixed some bugs in Router and minor API changes (PR#151)
  • v0.6 Changes

    July 13, 2020

    ๐Ÿ’ฅ 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 [email protected] class Model(val id: String, val value: String)// in jsMainval 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)
  • v0.5 Changes

    June 11, 2020

    ๐Ÿ’ฅ 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
  • v0.4 Changes

    May 26, 2020

    ๐Ÿ’ฅ 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'}
    
  • v0.3 Changes

    April 22, 2020
    • ๐Ÿ›  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
  • v0.2 Changes

    March 19, 2020

    ๐Ÿš€ First automated release using github actions...

  • v0.1 Changes

    February 28, 2020

    ๐Ÿš€ Our first public release, just to test the build- and publish-process.