Skip to content

Commit

Permalink
Updated core components to the latest react features
Browse files Browse the repository at this point in the history
  • Loading branch information
viktor-podzigun committed Jul 9, 2019
1 parent fc8acae commit 3b1ce71
Show file tree
Hide file tree
Showing 15 changed files with 1,900 additions and 1,946 deletions.
2,881 changes: 1,441 additions & 1,440 deletions docs/showcase/assets/scommons-client-showcase-opt.js

Large diffs are not rendered by default.

12 changes: 5 additions & 7 deletions ui/src/main/scala/scommons/client/ui/HTML.scala
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
package scommons.client.ui

import io.github.shogowada.scalajs.reactjs.React
import io.github.shogowada.scalajs.reactjs.VirtualDOM._
import io.github.shogowada.scalajs.reactjs.classes.ReactClass
import io.github.shogowada.scalajs.reactjs.VirtualDOM.VirtualDOMAttributes
import io.github.shogowada.statictags.{Attribute, AttributeSpec}
import scommons.react.UiComponent
import scommons.react._

import scala.scalajs.js

case class HTMLProps(htmlText: String, wordWrap: Boolean)

object HTML extends UiComponent[HTMLProps] {
object HTML extends FunctionComponent[HTMLProps] {

protected def create(): ReactClass = React.createClass[PropsType, Unit] { self =>
val props = self.props.wrapped
protected def render(compProps: Props): ReactElement = {
val props = compProps.wrapped

<.div(
if (props.wordWrap) None
Expand Down
90 changes: 37 additions & 53 deletions ui/src/main/scala/scommons/client/ui/ImageButton.scala
Original file line number Diff line number Diff line change
@@ -1,67 +1,51 @@
package scommons.client.ui

import io.github.shogowada.scalajs.reactjs.React
import io.github.shogowada.scalajs.reactjs.VirtualDOM._
import io.github.shogowada.scalajs.reactjs.classes.ReactClass
import io.github.shogowada.scalajs.reactjs.events.MouseSyntheticEvent
import org.scalajs.dom.raw.HTMLButtonElement
import scommons.react.UiComponent
import scommons.react._
import scommons.react.hooks._

case class ImageButtonProps(data: ImageButtonData,
onClick: () => Unit,
disabled: Boolean = false,
showTextAsTitle: Boolean = false,
requestFocus: Boolean = false)

object ImageButton extends UiComponent[ImageButtonProps] {

private case class ImageButtonState(setButtonRef: HTMLButtonElement => Unit,
getButtonRef: () => HTMLButtonElement)

protected def create(): ReactClass = React.createClass[PropsType, ImageButtonState](
getInitialState = { _ =>
var buttonRef: HTMLButtonElement = null

ImageButtonState({ ref =>
buttonRef = ref
}, { () =>
buttonRef
})
},
componentDidUpdate = { (self, prevProps, _) =>
val buttonRef = self.state.getButtonRef()
if (self.props.wrapped.requestFocus
&& self.props.wrapped.requestFocus != prevProps.wrapped.requestFocus) {

buttonRef.focus()
}
},
render = { self =>
val props = self.props.wrapped
val data = props.data

val image = if (props.disabled) data.disabledImage else data.image
val primaryClass = if (data.primary) "btn-primary" else ""

val attributes = (
if (props.showTextAsTitle) Some(^.title := data.text)
else None
) :: List(
^.`type` := "button",
^.className := s"btn $primaryClass",
^.disabled := props.disabled,
^.ref := { ref: HTMLButtonElement =>
self.state.setButtonRef(ref)
},
^.onClick := { _: MouseSyntheticEvent =>
self.props.wrapped.onClick()
object ImageButton extends FunctionComponent[ImageButtonProps] {

protected def render(compProps: Props): ReactElement = {
val buttonRef = useRef[HTMLButtonElement](null)
val props = compProps.wrapped

useLayoutEffect({ () =>
val button = buttonRef.current
if (button != null) {
if (props.requestFocus) {
button.focus()
}
)
}
}, List(props.requestFocus))

val data = props.data
val image = if (props.disabled) data.disabledImage else data.image
val primaryClass = if (data.primary) "btn-primary" else ""

val attributes = (
if (props.showTextAsTitle) Some(^.title := data.text)
else None
) :: List(
^.`type` := "button",
^.className := s"btn $primaryClass",
^.disabled := props.disabled,
^.reactRef := buttonRef,
^.onClick := { _: MouseSyntheticEvent =>
props.onClick()
}
)

<.button(attributes)(
if (props.showTextAsTitle) ImageLabelWrapper(image, None)
else ImageLabelWrapper(image, Some(data.text))
)
}
)
<.button(attributes)(
if (props.showTextAsTitle) ImageLabelWrapper(image, None)
else ImageLabelWrapper(image, Some(data.text))
)
}
}
84 changes: 34 additions & 50 deletions ui/src/main/scala/scommons/client/ui/ImageCheckBox.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package scommons.client.ui

import io.github.shogowada.scalajs.reactjs.React
import io.github.shogowada.scalajs.reactjs.VirtualDOM._
import io.github.shogowada.scalajs.reactjs.classes.ReactClass
import io.github.shogowada.scalajs.reactjs.events.FormSyntheticEvent
import org.scalajs.dom.raw.HTMLInputElement
import scommons.react.UiComponent
import scommons.react._
import scommons.react.hooks._

import scala.scalajs.js

case class ImageCheckBoxProps(value: TriState,
image: String,
Expand All @@ -22,56 +22,40 @@ case class ImageCheckBoxProps(value: TriState,
* @see http://css-tricks.com/indeterminate-checkboxes/
* @see https://github.com/facebook/react/issues/1798#issuecomment-333414857
*/
object ImageCheckBox extends UiComponent[ImageCheckBoxProps] {

private case class ImageCheckBoxState(setInputRef: HTMLInputElement => Unit,
getInputRef: () => HTMLInputElement)

protected def create(): ReactClass = React.createClass[PropsType, ImageCheckBoxState](
getInitialState = { _ =>
var inputRef: HTMLInputElement = null

ImageCheckBoxState({ ref =>
inputRef = ref
}, { () =>
inputRef
})
},
componentDidMount = { self =>
val inputRef = self.state.getInputRef()
inputRef.indeterminate = self.props.wrapped.value == TriState.Indeterminate
},
componentDidUpdate = { (self, prevProps, _) =>
val inputRef = self.state.getInputRef()
object ImageCheckBox extends FunctionComponent[ImageCheckBoxProps] {

if (self.props.wrapped.value != prevProps.wrapped.value) {
inputRef.indeterminate = self.props.wrapped.value == TriState.Indeterminate
protected def render(compProps: Props): ReactElement = {
val inputRef = useRef[HTMLInputElement](null)
val props = compProps.wrapped

useLayoutEffect({ () =>
val input = inputRef.current
if (input != null) {
input.indeterminate = props.value == TriState.Indeterminate
}

if (self.props.wrapped.requestFocus
&& self.props.wrapped.requestFocus != prevProps.wrapped.requestFocus) {

inputRef.focus()
}, List(props.value.asInstanceOf[js.Any]))

useLayoutEffect({ () =>
val input = inputRef.current
if (input != null) {
if (props.requestFocus) {
input.focus()
}
}
},
render = { self =>
val props = self.props.wrapped
}, List(props.requestFocus))

<.label()(
<.input(
^.`type` := "checkbox",
^.checked := TriState.isSelected(props.value),
^.ref := { ref: HTMLInputElement =>
self.state.setInputRef(ref)
},
^.onChange := onChange(props.readOnly) { () =>
props.onChange(props.value.next)
}
)(),
ImageLabelWrapper(props.image, Some(props.text))
)
}
)
<.label()(
<.input(
^.`type` := "checkbox",
^.checked := TriState.isSelected(props.value),
^.reactRef := inputRef,
^.onChange := onChange(props.readOnly) { () =>
props.onChange(props.value.next)
}
)(),
ImageLabelWrapper(props.image, Some(props.text))
)
}

private[ui] def onChange(readOnly: Boolean)
(f: () => Unit): FormSyntheticEvent[HTMLInputElement] => Unit = { event =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package scommons.client.ui

import io.github.shogowada.scalajs.reactjs.VirtualDOM._
import io.github.shogowada.statictags.Element
import scommons.react._

/**
* Common implementation for image with optional label.
Expand Down
100 changes: 43 additions & 57 deletions ui/src/main/scala/scommons/client/ui/PasswordField.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package scommons.client.ui

import io.github.shogowada.scalajs.reactjs.React
import io.github.shogowada.scalajs.reactjs.VirtualDOM._
import io.github.shogowada.scalajs.reactjs.classes.ReactClass
import io.github.shogowada.scalajs.reactjs.events.{FormSyntheticEvent, KeyboardSyntheticEvent}
import org.scalajs.dom.ext.KeyCode
import org.scalajs.dom.raw.HTMLInputElement
import scommons.react.UiComponent
import scommons.react._
import scommons.react.hooks._

case class PasswordFieldProps(password: String,
onChange: (String) => Unit,
Expand All @@ -17,63 +15,51 @@ case class PasswordFieldProps(password: String,
onEnter: () => Unit = () => (),
readOnly: Boolean = false)

object PasswordField extends UiComponent[PasswordFieldProps] {
object PasswordField extends FunctionComponent[PasswordFieldProps] {

private case class PasswordFieldState(setInputRef: HTMLInputElement => Unit,
getInputRef: () => HTMLInputElement)

protected def create(): ReactClass = React.createClass[PropsType, PasswordFieldState](
getInitialState = { _ =>
var inputRef: HTMLInputElement = null

PasswordFieldState({ ref =>
inputRef = ref
}, { () =>
inputRef
})
},
componentDidUpdate = { (self, prevProps, _) =>
val inputRef = self.state.getInputRef()
val value = inputRef.value
if (self.props.wrapped.requestSelect
&& self.props.wrapped.requestSelect != prevProps.wrapped.requestSelect
&& value.nonEmpty) {

inputRef.setSelectionRange(0, value.length)
protected def render(compProps: Props): ReactElement = {
val inputRef = useRef[HTMLInputElement](null)
val props = compProps.wrapped

useLayoutEffect({ () =>
val input = inputRef.current
if (input != null) {
val value = input.value
if (props.requestSelect && value.nonEmpty) {
input.setSelectionRange(0, value.length)
}
}
}, List(props.requestSelect))

if (self.props.wrapped.requestFocus
&& self.props.wrapped.requestFocus != prevProps.wrapped.requestFocus) {

inputRef.focus()
useLayoutEffect({ () =>
val input = inputRef.current
if (input != null) {
if (props.requestFocus) {
input.focus()
}
}
},
render = { self =>
val props = self.props.wrapped
}, List(props.requestFocus))

<.input(
^("readOnly") := props.readOnly,
^.`type` := "password",
props.className.map { className =>
^.className := className
},
^.value := props.password,
props.placeholder.map { placeholder =>
^.placeholder := placeholder
},
^.ref := { ref: HTMLInputElement =>
self.state.setInputRef(ref)
},
^.onChange := { e: FormSyntheticEvent[HTMLInputElement] =>
val value = e.target.value
props.onChange(value)
},
^.onKeyDown := { e: KeyboardSyntheticEvent =>
if (e.keyCode == KeyCode.Enter) {
props.onEnter()
}
<.input(
^("readOnly") := props.readOnly,
^.`type` := "password",
props.className.map { className =>
^.className := className
},
^.value := props.password,
props.placeholder.map { placeholder =>
^.placeholder := placeholder
},
^.reactRef := inputRef,
^.onChange := { e: FormSyntheticEvent[HTMLInputElement] =>
val value = e.target.value
props.onChange(value)
},
^.onKeyDown := { e: KeyboardSyntheticEvent =>
if (e.keyCode == KeyCode.Enter) {
props.onEnter()
}
)()
}
)
}
)()
}
}
Loading

0 comments on commit 3b1ce71

Please sign in to comment.