Skip to content

Commit

Permalink
Examples. Table. Refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
porotkin committed Jan 20, 2025
1 parent 607d6fe commit b03ffff
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ package wrappers.example.list
import react.FC
import react.dom.html.ReactHTML.div
import wrappers.example.table.UserTable
import wrappers.example.table.selection.TableSelectionModule

val UserList = FC {
div {
CreateUserButton()

UserTable()
TableSelectionModule {
UserTable()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,14 @@ package wrappers.example.table.selection

import react.FC
import react.PropsWithValue
import react.dom.events.ChangeEvent
import react.useCallback
import react.useMemo
import tanstack.table.core.Row
import web.html.HTMLInputElement

internal val SelectionCell: FC<PropsWithValue<Row<*>>> = FC { props ->
val rowId = props.value.id
internal val SelectionCell: FC<PropsWithValue<SelectedKeys>> = FC { props ->
val keys = props.value

val changeHandler = useCallback(rowId) { _: ChangeEvent<HTMLInputElement> ->
if (selectedKeys.value.contains(rowId)) {
selectedKeys.value = selectedKeys.value.filterNot { it in rowId }.toTypedArray()
} else {
selectedKeys.value += rowId
}
}


val rowIdArray = useMemo(rowId) {
arrayOf(rowId)
}
val changeHandler = useSelectionChangeHandler(keys)

SelectionCheckbox {
value = rowIdArray
value = keys
onChange = changeHandler
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package wrappers.example.table.selection

import preact.signals.react.runtime.useSignals
import preact.signals.react.useComputed
import react.FC
import react.PropsWithValue
import react.dom.events.ChangeEvent
Expand All @@ -16,9 +15,7 @@ internal external interface SelectionCheckboxProps : PropsWithValue<SelectedKeys
internal val SelectionCheckbox: FC<SelectionCheckboxProps> = FC { props ->
useSignals() // for preact signals to re-render the component on change without Babel plugin

val isChecked = useComputed {
props.value.all { selectedKeys.value.contains(it) }
}
val isChecked = useIsChecked(props.value)

input {
type = checkbox
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package wrappers.example.table.selection

import preact.signals.react.useSignal
import react.FC
import react.PropsWithChildren
import react.useCallback
import wrappers.example.entities.Key

internal val TableSelectionModule: FC<PropsWithChildren> = FC { props ->
val selection = useSignal(EMPTY_SELECTION)

val selectionHandler: SelectionHandler<Key> = useCallback { keys ->
val (add, remove) = keys.entries
.partition { it.value }

selection.value = selection.value - remove.toSelectedKeys() + add.toSelectedKeys()
}

SelectedKeysContext(selection) {
SelectionHandlerContext(selectionHandler) {
+props.children
}
}
}

private fun List<Map.Entry<Key, Boolean>>.toSelectedKeys(): SelectedKeys =
map { it.key }.toSet()
Original file line number Diff line number Diff line change
@@ -1,38 +1,34 @@
package wrappers.example.table.selection

import js.array.ReadonlyArray
import js.objects.jso
import preact.signals.core.Signal
import preact.signals.core.signal
import react.create
import tanstack.table.core.ColumnDef
import tanstack.table.core.ColumnDefTemplate
import tanstack.table.core.StringOrTemplateHeader

internal typealias SelectedKeys = ReadonlyArray<String>

internal val selectedKeys: Signal<SelectedKeys> = signal(emptyArray())
internal val EMPTY_SELECTION: SelectedKeys = emptySet()
internal typealias SelectedKeys = Set<String>

internal fun <T : Any> createSelectionColumn(): ColumnDef<T, String> =
jso {
id = "selection"
size = 32
header = StringOrTemplateHeader(
ColumnDefTemplate { context ->
val allRowIds = context.table.getRowModel().rows
val keys = context.table.getRowModel().rows
.map { it.id }
.toTypedArray()
.toSet()

SelectionHeader.create {
value = allRowIds
SelectionCell.create {
value = keys
}
}
)
cell = ColumnDefTemplate { context ->
val row = context.cell.row
val keys = setOf(context.cell.row.id)

SelectionCell.create {
value = row
value = keys
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package wrappers.example.table.selection

import preact.signals.core.ReadonlySignal
import preact.signals.react.useComputed

internal fun useIsChecked(keys: SelectedKeys): ReadonlySignal<Boolean> {
val selection = useSelectedKeys()

return useComputed {
selection.value.containsAll(keys)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package wrappers.example.table.selection

import preact.signals.core.Signal
import react.RequiredContext
import react.createRequiredContext
import react.useRequired

internal val SelectedKeysContext: RequiredContext<Signal<SelectedKeys>> =
createRequiredContext()

internal fun useSelectedKeys(): Signal<SelectedKeys> =
useRequired(SelectedKeysContext)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package wrappers.example.table.selection

import react.dom.events.ChangeEvent
import react.useCallback
import web.html.HTMLInputElement

internal fun useSelectionChangeHandler(keys: SelectedKeys): (ChangeEvent<HTMLInputElement>) -> Unit {
val selectionHandler = useSelectionHandler()

return useCallback(keys) { event ->
selectionHandler(keys.associateWith { event.target.checked })
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package wrappers.example.table.selection

import react.RequiredContext
import react.createRequiredContext
import react.useRequired
import wrappers.example.entities.Key

typealias SelectionHandler<T> = (Map<T, Boolean>) -> Unit

internal val SelectionHandlerContext: RequiredContext<SelectionHandler<Key>> =
createRequiredContext()

internal fun useSelectionHandler(): SelectionHandler<Key> =
useRequired(SelectionHandlerContext)

0 comments on commit b03ffff

Please sign in to comment.