Skip to content

Commit

Permalink
migrate table hooks to monadic
Browse files Browse the repository at this point in the history
  • Loading branch information
rpiaggio committed Dec 24, 2024
1 parent a6ce6de commit b20b82f
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 59 deletions.
6 changes: 3 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import org.scalajs.linker.interface.ModuleSplitStyle

ThisBuild / tlBaseVersion := "0.126"
ThisBuild / tlBaseVersion := "0.127"
ThisBuild / tlCiReleaseBranches := Seq("master")

val Versions = new {
Expand All @@ -17,7 +17,7 @@ val Versions = new {
val log4catsLogLevel = "0.3.1"
val lucumaCore = "0.112.1"
val lucumaPrimeStyles = "0.3.0"
val lucumaReact = "0.76.0"
val lucumaReact = "0.77.0"
val lucumaRefined = "0.1.2"
val lucumaSchemas = "0.110.3"
val lucumaSso = "0.7.2"
Expand All @@ -42,7 +42,7 @@ ThisBuild / turbo := true
ThisBuild / Test / parallelExecution := false
ThisBuild / scalaVersion := "3.6.2"
ThisBuild / crossScalaVersions := Seq("3.6.2")
ThisBuild / scalacOptions ++= Seq("-language:implicitConversions")
ThisBuild / scalacOptions ++= Seq("-language:implicitConversions", "-explain-cyclic")

enablePlugins(NoPublishPlugin)

Expand Down
13 changes: 7 additions & 6 deletions modules/ui/src/main/scala/lucuma/ui/hooks/UseTheme.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@

package lucuma.ui.hooks

import crystal.react.*
import crystal.react.View
import crystal.react.hooks.*
import japgolly.scalajs.react.*
import japgolly.scalajs.react.hooks.CustomHook
import lucuma.ui.enums.Theme

def useTheme(initial: => Theme): HookResult[View[Theme]] =
for
theme <- useStateView(initial)
_ <- useEffectOnMount(Theme.init(initial) >>= theme.set)
yield theme.withOnMod(_.mount)

private object UseTheme:
def useTheme(initial: => Theme): HookResult[View[Theme]] =
for
theme <- useStateView(initial)
_ <- useEffectOnMount(Theme.init(initial) >>= theme.set)
yield theme.withOnMod(_.mount)

private val hook: CustomHook[Theme, View[Theme]] =
CustomHook.fromHookResult(useTheme(_))
Expand Down
2 changes: 0 additions & 2 deletions modules/ui/src/main/scala/lucuma/ui/hooks/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,4 @@

package lucuma.ui.hooks

export UseTheme.useTheme

export UseTheme.syntax.*
24 changes: 11 additions & 13 deletions modules/ui/src/main/scala/lucuma/ui/table/hooks/UseDynTable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,23 @@ class UseDynTable(
export colState.{computedVisibility => columnVisibility, resized => columnSizing}

object UseDynTable:
private val hook = CustomHook[(DynTable, SizePx)] // (dynTable, width)
.useStateBy(_._1.initialState) // colState
.useEffectWithDepsBy((props, _) => props._2): (props, colState) =>
width => // Recompute columns upon resize
CallbackTo:
props._1.adjustColSizes(width)(colState.value)
.flatMap:
colState.setState(_)
.buildReturning: (props, colState) =>
val (dynTable, width) = props

def useDynTable(dynTableDef: DynTable, width: SizePx): HookResult[UseDynTable] =
for
colState <- useState(dynTableDef.initialState)
_ <- useEffectWithDeps(width): w => // Recompute columns upon resize
CallbackTo(dynTableDef.adjustColSizes(w)(colState.value)) >>= colState.setState
yield
def onColumnSizingChangeHandler(updater: Updater[ColumnSizing]): Callback =
colState.modState: oldState =>
dynTable.adjustColSizes(width):
dynTableDef.adjustColSizes(width):
updater match
case Updater.Set(v) => DynTable.ColState.resized.replace(v)(oldState)
case Updater.Mod(fn) => DynTable.ColState.resized.modify(fn)(oldState)

UseDynTable(dynTable.columnSizes, colState.value, onColumnSizingChangeHandler)
UseDynTable(dynTableDef.columnSizes, colState.value, onColumnSizingChangeHandler)

private val hook: CustomHook[(DynTable, SizePx), UseDynTable] =
CustomHook.fromHookResult(useDynTable(_, _))

object HooksApiExt {
sealed class Primary[Ctx, Step <: HooksApi.AbstractStep](api: HooksApi.Primary[Ctx, Step]):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,42 +23,44 @@ private object UseReactTableWithStateStore:

private object CanSave extends NewType[Boolean]

private def hook[T, M] =
CustomHook[TableOptionsWithStateStore[DefaultA, T, M]]
.useReactTableBy(_.tableOptions)
.useState(PrefsLoaded(false))
.useRef(CanSave(false))
.useEffectOnMountBy((props, table, prefsLoadad, canSave) =>
(props.stateStore.load() >>=
(mod =>
val newState: TableState = mod(table.getState())
def useReactTableWithStateStore[T, M](
options: TableOptionsWithStateStore[DefaultA, T, M]
): HookResult[Table[T, M]] =
for
table <- useReactTable(options.tableOptions)
prefsLoadad <- useState(PrefsLoaded(false))
canSave <- useRef(CanSave(false))
_ <- useEffectOnMount:
(options.stateStore.load() >>=
(mod =>
val newState: TableState = mod(table.getState())

// We apply partial state changes in case there are partial state overrides.
table.setColumnVisibility(newState.columnVisibility).to[DefaultA] >>
// table.setColumnOrder(newState.columnOrder).to[DefaultA] >> // Not implemented yet in lucuma-react
table.setColumnPinning(newState.columnPinning).to[DefaultA] >>
table.setRowPinning(newState.rowPinning).to[DefaultA] >>
table.setSorting(newState.sorting).to[DefaultA] >>
table.setExpanded(newState.expanded).to[DefaultA] >>
table.setColumnSizing(newState.columnSizing).to[DefaultA] >>
table.setColumnSizingInfo(newState.columnSizingInfo).to[DefaultA] >>
table.setRowSelection(newState.rowSelection).to[DefaultA] >>
prefsLoadad.setStateAsync(PrefsLoaded(true))
))
.guaranteeCase(outcome => canSave.setAsync(CanSave(true)).unlessA(outcome.isSuccess))
)
.useEffectWithDepsBy((_, table, _, _) => table.getState())((props, _, prefsLoadad, canSave) =>
state =>
// Don't save prefs while we are still attempting to load them or if we just loaded them.
props.stateStore
.save(state)
.whenA(canSave.value.value)
>>
canSave
.setAsync(CanSave(true))
.whenA(prefsLoadad.value.value && !canSave.value.value)
)
.buildReturning((_, table, _, _) => table)
// We apply partial state changes in case there are partial state overrides.
table.setColumnVisibility(newState.columnVisibility).to[DefaultA] >>
// table.setColumnOrder(newState.columnOrder).to[DefaultA] >> // Not implemented yet in lucuma-react
table.setColumnPinning(newState.columnPinning).to[DefaultA] >>
table.setRowPinning(newState.rowPinning).to[DefaultA] >>
table.setSorting(newState.sorting).to[DefaultA] >>
table.setExpanded(newState.expanded).to[DefaultA] >>
table.setColumnSizing(newState.columnSizing).to[DefaultA] >>
table.setColumnSizingInfo(newState.columnSizingInfo).to[DefaultA] >>
table.setRowSelection(newState.rowSelection).to[DefaultA] >>
prefsLoadad.setStateAsync(PrefsLoaded(true))
))
.guaranteeCase(outcome => canSave.setAsync(CanSave(true)).unlessA(outcome.isSuccess))
_ <- useEffectWithDeps(table.getState()): state =>
// Don't save prefs while we are still attempting to load them or if we just loaded them.
options.stateStore
.save(state)
.whenA(canSave.value.value)
>>
canSave
.setAsync(CanSave(true))
.whenA(prefsLoadad.value.value && !canSave.value.value)
yield table

private def hook[T, M]: CustomHook[TableOptionsWithStateStore[DefaultA, T, M], Table[T, M]] =
CustomHook.fromHookResult(useReactTableWithStateStore(_))

object HooksApiExt:
sealed class Primary[Ctx, Step <: HooksApi.AbstractStep](api: HooksApi.Primary[Ctx, Step]):
Expand Down
2 changes: 2 additions & 0 deletions modules/ui/src/main/scala/lucuma/ui/table/hooks/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@

package lucuma.ui.table.hooks

export UseDynTable.useDynTable, UseReactTableWithStateStore.useReactTableWithStateStore

export UseDynTable.syntax.*, UseReactTableWithStateStore.syntax.*

0 comments on commit b20b82f

Please sign in to comment.