Version 0.12
Breaking Changes
PR #494: Allow sub()
on all Store
s
Removes the RootStore
dependency in the SubStore
, so that SubStore
s can be created by calling sub()
function implemented in Store
interface. Therefore it is now possible to create a SubStore
from every Store
object.
Because one SubStore
generic type gets obsolete, it will break existing code, but it is easy to fix that. Just remove the first not type parameter.
// before
class SubStore<R, P, T> {}
// now
class SubStore<P, T> {}
// before
val addressSub: SubStore<Person, Person, Address> = store.sub(addressLens)
// now
val addressSub: SubStore<Person, Address> = store.sub(addressLens)
PR #492: Remove deprecated direction
-api from RadioGroupComponent
and CheckboxGroupComponent
This PR removes the deprecated direction
-api from RadioGroupComponent
and CheckboxGroupComponent
.
Use orientation instead
.
PR #489: Some Improvements and Bugfixing around Forms
Improve FormControl code
- make
FormSizeSpecifier
values uppercase, so more Kotlin alike - improve render strategies initialization and customization: Instead of setting all up within the
init
block, there is now a new private methodinitRenderStrategies
that produces the mapping and is directly called at beginning of the rendering process. This way nothis
pointer is leaked as before. For custom implementations there is now a protected hook functionfinalizeRenderStrategies
that can be used to extend or change the renderer strategies!
Migration Guide:
If a custom renderer should be applied or a new factory should be added, custom implementation of FormControlComponent
must replace the old registerRenderStrategy
within the init
block by a new mechanism:
// old way, no more possible!
class MyFormControlComponent : FormControlComponent {
init {
registerRenderStrategy("radioGroupWithInput", ControlGroupRenderer(this))
}
}
// new way, override `finalizeRenderStrategies` method:
class MyFormControlComponent : FormControlComponent {
// some new factory: `creditCardInput` with key of same name; used with `SingleControlRenderer`
// another new factory: `colorInput` with key of same name and new renderer
override fun finalizeRenderStrategies(
strategies: MutableMap<String, ControlRenderer>,
single: ControlRenderer,
group: ControlRenderer
) {
// override setup for a built-in factory:
strategies.put(ControlNames.textArea, MySpecialRendererForTextAreas(this))
// register new factory
strategies.put("creditCardInput", single)
// register new factory with new renderer
strategies.put("colorInput", ColorInputRenderer(this))
}
}
Improve sizes aspect for components in theme
- in respect to EfC 502 a new mixin alike interface
FormSizesAware
has been introduced - the
FormSizes
interface is renamed toFormSizesStyles
Migration Guide:
If a component supports a size property and relies on the old FormSizes
interface, just rename the receiver type appropriate to `FormSizesStyles``:
// old
val size = ComponentProperty<FormSizes.() -> Style<BasicParams>> { Theme().someComponent.sizes.normal }
// new
val size = ComponentProperty<FormSizesStyles.() -> Style<BasicParams>> { Theme().someComponent.sizes.normal }
// ^^^^^^^^^^^^^^^
// choose new name
Make FormControl Labels dynamic
- the
label
property of a FormControl now accepts alsoFlow<String>
. Thus the label can dynamically react to some other state changing.
Migration Guide
The code for a ControlRenderer
implementation needs to be adapted. Use the following recipe:
class ControlGroupRenderer(private val component: FormControlComponent) : ControlRenderer {
override fun render(/*...*/) {
// somewhere the label gets rendered (label / legend or alike)
label {
// old:
+component.label.value
// change to:
component.label.values.asText()
}
}
}
Adapt FormControl's textArea function parameters
- the optional store parameter now also is named
value
like as within the maintextArea
factory.
Repairs label behaviour for SelectField
- a click onto a label within a FormControl now directs to the SelectField.
- the id of a SelectField is now correctly set, so that a FormControl can now fill the
for
attribute of the label correctly.
PR #490: Move Modal’s close handler into content property
Until now the close
handler was injected directly into the main configuration scope of a modal. With repsect to EfC 416 this is now changed. The handler only gets injected into the content
property, where it is considered to be used.
Migration
Just move the handler parameter from the build
expression of modal into the content
property:
// old
clickButton {
text("Custom Close Button")
} handledBy modal { close -> // injected at top level
content {
clickButton {icon { logOut } } handledBy close
}
}
// new
clickButton {
text("Custom Close Button")
} handledBy modal {
content { close -> // injected only within content
clickButton {icon { logOut } } handledBy close
}
}
PR #487: Rework ToastComponent
Changes
This PR cleans up the ToastComponent
code. This includes:
- Adding styling-options to the theme
- Use correct z-indizes
- General code-cleanup
What's API breaking?
Theme().toast.base
has been renamed toTheme().toast.body
and might break themes that have custom toast-styles
New Features
PR #505: Add TooltipComponent
This PR deals with the new TooltipComponent
A tooltip
should be used to display fast information for the user.
The individual text
will be shown on hover the RenderContext
in which be called.
This class offers the following configuration features:
text
can be avararg
, a flow, a list, a flow of list of String or a simple string, optional can be use the @PropertytextFromParam
.placement
of thetext
around theRenderContext
in which be called. Available placements aretop
,topStart
,topEnd
,bottom
,bottomStart
,bottomEnd
,left
,leftStart
,leftEnd
,right
,rightStart
,rightEnd
.
Example usage:
span {
+"hover me"
tooltip("my Tooltip on right side") {
placement { right }
}
}
span {
+"hover me to see a multiline tooltip"
tooltip("first line", "second line"){}
}
span {
+"hover me for custom colored tooltip"
tooltip({
color { danger.mainContrast }
background {
color { danger.main }
}
}) {
text(listOf("first line", "second line"))
placement { TooltipComponent.PlacementContext.bottomEnd }
}
}
Migration
- The old tooltip component remains as deprecated for the next releases, so clients have time to migrate.
Motivation
The old Tooltip component is based upon pure CSS. This is fine for basic usage, but it fails when it comes to advanced features like automatic positioning. Also the API does not fit into the "fritz2 component style". That's why there is the need to rework the tooltip.
PR #493: Add PopupComponent
The PopupComponent
should be used for to positioning content
like tooltip
or popover
automatically in the right place near a trigger
.
A popup
mainly consists of a trigger
(the Element(s)) which calls the content
.
It can cen configured by
offset
the space (in px) betweentrigger
andcontent
flipping
if no space on chosen available it will be find a right placement automaticallyplacement
of thecontent
around thetrigger
The trigger
provides two handler which can be used, the first is important to open/toggle the content
the second close it.
content
provides one handler which can be used to close it.
Example:
popup {
offset(10.0)
flipping(false)
placement { topStart }
trigger { toggle, close ->
span {
+"hover me"
mouseenters.map { it.currentTarget } handledBy toggle
mouseleaves.map { } handledBy close
}
}
content { close ->
div {
+"my content"
clicks.map{ } handledBy close
}
}
}
PR #496: Add PaperComponent
and CardComponent
This PR adds a new CardComponent
that behaves similar to the old PopoverComponent
s content.
Paper Component
Component displaying content in a card-like box that can either appear elevated or outlined and scales with the specified size
of the component.
Example
paper {
size { /* small | normal | large */ }
type { /* normal | outline | ghost */ }
content {
// ...
}
}
CardComponent
A component displaying the typical sections of a card inside a PaperComponent
.
The available sections are a header, a footer and the actual content.
Example
card {
size { /* small | normal | large */ }
type { /* normal | outline | ghost */ }
header {
// ...
}
content {
// ...
}
footer {
// ...
}
}
PR #481: Add possibility to pass arbitrary payload data in fritz2's DSL
In fritz2 you can now put some arbitrary payload data to every fritz2 html element (for styled elements too) and receive this payload data later (or deeper) in your html tree. This possibility can be use to know in with kind of context your own component get rendered or you can provide some additional information to your context for making decision on styling or rendering.
Example:
enum class Sizes {
SMALL, NORMAL, LARGE;
companion object {
val key = keyOf<Sizes>()
}
}
fun main() {
render {
div {
div(scope = {
set(Sizes.key, Sizes.SMALL)
}) {
section {
scope.asDataAttr()
when (scope[Sizes.key]) {
Sizes.SMALL -> div({ fontSize { small } }) { +"small text" }
Sizes.NORMAL -> div({ fontSize { normal } }) { +"normal text" }
Sizes.LARGE -> div({ fontSize { large } }) { +"large text" }
else -> div { +"no size in scope available" }
}
}
}
p {
scope.asDataAttr()
// scope is context-based and therefore scope is here empty
+"no scope entries here (context-based)"
}
}
}
}
PR #470: Add TypeAheadComponent
Adds a TypeAhead component to fritz2's component portfolio.
A TypeAhead offers the possibility to input some string and get some list of proposals to choose from. This is reasonable for large static lists, that can't be managed by SelectFields or RadioGroups or where the proposals rely on a remote resource.
Example usage:
val proposals = listOf("Kotlin", "Scala", "Java", "OCaml", "Haskell").asProposals()
val choice = storeOf("")
typeAhead(value = choice, items = proposals) { }
For further details have a look at our KitchenSink
Improvements
PR #514: Upgrade Kotlin to Version 1.5.30
PR #507: Add TooltipMixin
and TooltipProperties
to use TooltipComponent
in Components
more easily
With this PR it beeing easier to integrate a tooltip in a component and the user get a same usage of a tooltip.
PR #486: Use colors in appFrame
and added submenu
in menu
component
The appFrame
component uses now different ColorScheme
s to coloring itself.
The menu
component can now contain submenu
s:
menu {
header("Entries")
entry {
text("Basic entry")
}
divider()
custom {
pushButton {
text("I'm a custom entry")
}
}
submenu {
icon { menu }
text("Sub Menu")
entry {
icon { sun }
text("Entry with icon")
}
entry {
icon { ban }
text("Disabled entry")
disabled(true)
}
}
}
PR #483: Deprecate box
in favor of div
This PR deprecates the box
factory method in favor of div
because, in combination with fritz2.styling, it offers the exact same functionality. All calls of box
will have to be replaced eventually.
PR #477: Add convenience functions to create toasts with alert-content
This PR adds two convenience functions alertToast
and showAlertToast
which can be used to easily create toasts with alert's as their content.
New functions:
fun showAlertToast(
styling: BasicParams.() -> Unit = {},
baseClass: StyleClass = StyleClass.None,
id: String? = null,
prefix: String = "toast-alert",
build: AlertComponent.() -> Unit
)
fun alertToast(
styling: BasicParams.() -> Unit = {},
baseClass: StyleClass = StyleClass.None,
id: String? = null,
prefix: String = "toast-alert",
build: AlertComponent.() -> Unit
): SimpleHandler<Unit>
Example usage:
showAlertToast(buildToast = {
}) {
// toast-properties:
duration(6000)
// setup of the alert
alert {
title("Alert-Toast")
content("Alert in a toast")
severity { /* some severity */ }
variant { leftAccent }
}
}
// 'alertToast' is used similarly and bound to a flow like 'toast'
Previous usage
val alertComponent = AlertComponent()
.apply {
content("...")
stacking { toast }
}
showToast {
// adjust the close-button to match the alert's color-scheme:
closeButtonStyle(Theme().toast.closeButton.close + {
color {
val colorScheme = alertComponent.severity.value(Theme().alert.severities).colorScheme
when(alertComponent.variant.value(AlertComponent.VariantContext)) {
AlertComponent.AlertVariant.SUBTLE -> colorScheme.main
AlertComponent.AlertVariant.TOP_ACCENT -> colorScheme.main
AlertComponent.AlertVariant.LEFT_ACCENT -> colorScheme.main
else -> colorScheme.mainContrast
}
}
})
content {
alertComponent.render(this, styling, baseClass, id, prefix)
}
}
PR #462: Rename alert variant discreet
to ghost
This PR renames the discreet
alert-variant to ghost
in order to match the common naming scheme of fritz2.
All references of discreet
have to be changed:
alert {
variant { discreet } // <-- previously
variant { ghost } // <-- now
}