Skip to content

Commit

Permalink
Added ButtonBase facade and demo
Browse files Browse the repository at this point in the history
  • Loading branch information
viktor-podzigun committed Sep 21, 2021
1 parent 2bc0926 commit 16ed849
Show file tree
Hide file tree
Showing 36 changed files with 394 additions and 134 deletions.
1 change: 0 additions & 1 deletion core/src/main/scala/scommons/materialui/Button.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ object Button {
lazy val endIcon = ReactElementAttributeSpec("endIcon")
lazy val fullWidth = BooleanAttributeSpec("fullWidth")
lazy val startIcon = ReactElementAttributeSpec("startIcon")
lazy val variant = StringAttributeSpec("variant")
}

object ButtonAttributes {
Expand Down
28 changes: 28 additions & 0 deletions core/src/main/scala/scommons/materialui/ButtonBase.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package scommons.materialui

import io.github.shogowada.scalajs.reactjs.VirtualDOM.VirtualDOMAttributes
import io.github.shogowada.statictags._
import scommons.materialui.styles.Styles

/** @see https://material-ui.com/api/button-base/
*/
object ButtonBase {

trait ButtonBaseAttributes {

import ButtonBaseAttributes._

lazy val focusRipple = BooleanAttributeSpec("focusRipple")
lazy val focusVisibleClassName = StringAttributeSpec("focusVisibleClassName")
lazy val muiStyle = StyleAttributeSpec("style")
}

object ButtonBaseAttributes {

import VirtualDOMAttributes.Type._

case class StyleAttributeSpec(name: String) extends AttributeSpec {
def :=[T <: Styles](style: T): Attribute[T] = Attribute(name, style, AS_IS)
}
}
}
8 changes: 6 additions & 2 deletions core/src/main/scala/scommons/materialui/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ package object materialui {

implicit class MaterialUiVirtualDOMElements(elements: VirtualDOMElements) {
lazy val Button: ReactClassElementSpec = elements(raw.MaterialUiNative.Button)
lazy val ButtonBase: ReactClassElementSpec = elements(raw.MaterialUiNative.ButtonBase)
lazy val Icon: ReactClassElementSpec = elements(raw.MaterialUiNative.Icon)
lazy val IconButton: ReactClassElementSpec = elements(raw.MaterialUiNative.IconButton)
lazy val Typography: ReactClassElementSpec = elements(raw.MaterialUiNative.Typography)
}

object MaterialUiVirtualDOMAttributes {
Expand All @@ -27,13 +29,15 @@ package object materialui {
}

implicit class MaterialUiVirtualDOMAttributes(attributes: VirtualDOMAttributes)
extends Button.ButtonAttributes {
extends Button.ButtonAttributes
with ButtonBase.ButtonBaseAttributes {

import MaterialUiVirtualDOMAttributes._

lazy val color = StringAttributeSpec("color")
lazy val component = ComponentAttributeSpec("component")
lazy val fontSize = StringAttributeSpec("fontSize")
lazy val muSize = StringAttributeSpec("size")
lazy val muiSize = StringAttributeSpec("size")
lazy val variant = StringAttributeSpec("variant")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import scala.scalajs.js.annotation.JSImport
object MaterialUiNative extends js.Object {

val Button: ReactClass = js.native
val IconButton: ReactClass = js.native
val ButtonBase: ReactClass = js.native
val Icon: ReactClass = js.native
val IconButton: ReactClass = js.native
val Typography: ReactClass = js.native
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import scala.scalajs.js.|
@JSImport("@material-ui/core/styles", JSImport.Default)
object StylesNative extends js.Object {

val MuiThemeProvider: ReactClass = js.native
val ThemeProvider: ReactClass = js.native

def createTheme(options: js.Object, args: js.Object*): ThemeNative = js.native
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package object styles {
type WithStylesOptions = raw.WithStylesOptions

implicit class MaterialUiStylesVirtualDOMElements(elements: VirtualDOMElements) {
lazy val MuiThemeProvider: ReactClassElementSpec = elements(raw.StylesNative.MuiThemeProvider)
lazy val ThemeProvider: ReactClassElementSpec = elements(raw.StylesNative.ThemeProvider)
}

Expand Down
2 changes: 1 addition & 1 deletion showcase/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ sbt "project scommons-material-ui-showcase" fastOptJS::webpack

Then open the following file in your browser:
```bash
open ./showcase/index.dev.html
open ./showcase/target/scala-2.13/scalajs-bundler/main/index.dev.html
```
16 changes: 0 additions & 16 deletions showcase/index.dev.html

This file was deleted.

16 changes: 16 additions & 0 deletions showcase/src/main/resources/index.dev.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />

<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
</head>
<body>
<div id="root">Loading, please, wait...</div>

<script src="./scommons-material-ui-showcase-fastopt-library.js"></script>
<script src="./scommons-material-ui-showcase-fastopt-loader.js"></script>
<script src="./scommons-material-ui-showcase-fastopt.js"></script>
</body>
</html>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package scommons.materialui.showcase.button

import scommons.materialui._
import scommons.materialui.styles._
import scommons.react._

import scala.scalajs.js

object ButtonBases extends FunctionComponent[Unit] {

private[button] val images = List(
("static/images/image-list/breakfast.jpg", "Breakfast", "40%"),
("static/images/image-list/burgers.jpg", "Burgers", "30%"),
("static/images/image-list/camera.jpg", "Camera", "30%")
)

private[button] val useStyles = makeStyles(theme => {
val s = new Styles {
val root = new Styles {
val display = "flex"
val flexWrap = "wrap"
val minWidth = 300
val width = "100%"
}
val image = js.Dynamic.literal(
"position" -> "relative",
"height" -> 200,
theme.breakpoints.down("xs").asInstanceOf[String] -> {
val s = new Styles {
val width = "100% !important" // Overrides inline-style
val height = 100
}
s
},
s"&:hover, &$$focusVisible" -> {
val s = new Styles {
val zIndex = 1
val `& $imageBackdrop` = new Styles {
val opacity = 0.15
}
val `& $imageMarked` = new Styles {
val opacity = 0
}
val `& $imageTitle` = new Styles {
val border = "4px solid currentColor"
}
}
s
}
)
val focusVisible = new Styles {}
val imageButton = new Styles {
val position = "absolute"
val left = 0
val right = 0
val top = 0
val bottom = 0
val display = "flex"
val alignItems = "center"
val justifyContent = "center"
val color = theme.palette.common.white
}
val imageSrc = new Styles {
val position = "absolute"
val left = 0
val right = 0
val top = 0
val bottom = 0
val backgroundSize = "cover"
val backgroundPosition = "center 40%"
}
val imageBackdrop = new Styles {
val position = "absolute"
val left = 0
val right = 0
val top = 0
val bottom = 0
val backgroundColor = theme.palette.common.black
val opacity = 0.4
val transition = theme.transitions.create("opacity")
}
val imageTitle = new Styles {
val position = "relative"
val padding =
s"${theme.spacing(2)}px ${theme.spacing(4)}px ${theme.spacing(1).asInstanceOf[Int] + 6}px"
}
val imageMarked = new Styles {
val height = 3
val width = 18
val backgroundColor = theme.palette.common.white
val position = "absolute"
val bottom = -2
val left = "calc(50% - 9px)"
val transition = theme.transitions.create("opacity")
}
}
s
})

protected def render(compProps: Props): ReactElement = {
val classes = useStyles()

<.div(^.className := styleOf(classes.root))(
images.map { case (imageUrl, imageTitle, imageWidth) =>
<.ButtonBase(
^.focusRipple := true,
^.key := imageTitle,
^.className := styleOf(classes.image),
^.focusVisibleClassName := styleOf(classes.focusVisible),
^.muiStyle := new Styles {
val width = imageWidth
}
)(
<.span(
^.className := styleOf(classes.imageSrc),
^.muiStyle := new Styles {
val backgroundImage = s"url($imageUrl)"
}
)(),
<.span(^.className := styleOf(classes.imageBackdrop))(),
<.span(^.className := styleOf(classes.imageButton))(
<.Typography(
^.component := "span",
^.variant := "subtitle1",
^.color := "inherit",
^.className := styleOf(classes.imageTitle)
)(
imageTitle,
<.span(^.className := styleOf(classes.imageMarked))()
)
)
)
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ object ButtonDemos extends FunctionComponent[Unit] {
private[button] var iconLabelButtonsComp: UiComponent[Unit] = IconLabelButtons
private[button] var iconButtonsComp: UiComponent[Unit] = IconButtons
private[button] var customizedButtonsComp: UiComponent[Unit] = CustomizedButtons
private[button] var buttonBasesComp: UiComponent[Unit] = ButtonBases

protected def render(compProps: Props): ReactElement = {
<.div()(
Expand Down Expand Up @@ -53,7 +54,11 @@ object ButtonDemos extends FunctionComponent[Unit] {

<.h3()("Customized Buttons"),
<.hr()(),
<(customizedButtonsComp())()()
<(customizedButtonsComp())()(),

<.h3()("Complex Buttons"),
<.hr()(),
<(buttonBasesComp())()()
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import scommons.react._

object ButtonSizes extends FunctionComponent[Unit] {

private val useStyles = makeStyles(theme => {
private[button] val useStyles = makeStyles(theme => {
val s = new Styles {
val margin = new Styles {
val margin = theme.spacing(1)
Expand All @@ -21,40 +21,40 @@ object ButtonSizes extends FunctionComponent[Unit] {

<.div()(
<.div()(
<.Button(^.muSize := "small", ^.className := styleOf(classes.margin))(
<.Button(^.muiSize := "small", ^.className := styleOf(classes.margin))(
"Small"
),
<.Button(^.muSize := "medium", ^.className := styleOf(classes.margin))(
<.Button(^.muiSize := "medium", ^.className := styleOf(classes.margin))(
"Medium"
),
<.Button(^.muSize := "large", ^.className := styleOf(classes.margin))(
<.Button(^.muiSize := "large", ^.className := styleOf(classes.margin))(
"Large"
)
),
<.div()(
<.Button(^.variant := "outlined", ^.muSize := "small", ^.color := "primary", ^.className := styleOf(classes.margin))(
<.Button(^.variant := "outlined", ^.muiSize := "small", ^.color := "primary", ^.className := styleOf(classes.margin))(
"Small"
),
<.Button(^.variant := "outlined", ^.muSize := "medium", ^.color := "primary", ^.className := styleOf(classes.margin))(
<.Button(^.variant := "outlined", ^.muiSize := "medium", ^.color := "primary", ^.className := styleOf(classes.margin))(
"Medium"
),
<.Button(^.variant := "outlined", ^.muSize := "large", ^.color := "primary", ^.className := styleOf(classes.margin))(
<.Button(^.variant := "outlined", ^.muiSize := "large", ^.color := "primary", ^.className := styleOf(classes.margin))(
"Large"
)
),
<.div()(
<.Button(^.variant := "contained", ^.muSize := "small", ^.color := "primary", ^.className := styleOf(classes.margin))(
<.Button(^.variant := "contained", ^.muiSize := "small", ^.color := "primary", ^.className := styleOf(classes.margin))(
"Small"
),
<.Button(^.variant := "contained", ^.muSize := "medium", ^.color := "primary", ^.className := styleOf(classes.margin))(
<.Button(^.variant := "contained", ^.muiSize := "medium", ^.color := "primary", ^.className := styleOf(classes.margin))(
"Medium"
),
<.Button(^.variant := "contained", ^.muSize := "large", ^.color := "primary", ^.className := styleOf(classes.margin))(
<.Button(^.variant := "contained", ^.muiSize := "large", ^.color := "primary", ^.className := styleOf(classes.margin))(
"Large"
)
),
<.div()(
<.IconButton(^("aria-label") := "delete", ^.className := styleOf(classes.margin), ^.muSize := "small")(
<.IconButton(^("aria-label") := "delete", ^.className := styleOf(classes.margin), ^.muiSize := "small")(
<(ArrowDownwardIcon)(^.fontSize := "inherit")()
),
<.IconButton(^("aria-label") := "delete", ^.className := styleOf(classes.margin))(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import scommons.react._

object ContainedButtons extends FunctionComponent[Unit] {

private val useStyles = makeStyles(theme => {
private[button] val useStyles = makeStyles(theme => {
val s = new Styles {
val root = new Styles {
val `& > *` = new Styles {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ object CustomizedButtons extends FunctionComponent[Unit] {
s
})(<.Button.reactClass)

private val useStyles = makeStyles(theme => {
private[button] val useStyles = makeStyles(theme => {
val s = new Styles {
val margin = new Styles {
val margin = theme.spacing(1)
Expand All @@ -83,14 +83,18 @@ object CustomizedButtons extends FunctionComponent[Unit] {

private[button] lazy val defaultTheme = createTheme(new js.Object)

private[button] val nativeToTheme: js.Function1[NativeTheme, Theme] = { _ =>
theme
}

protected def render(compProps: Props): ReactElement = {
val classes = useStyles()

<.ThemeProvider(^.theme := defaultTheme)(
<(ColorButton)(^.variant := "contained", ^.color := "primary", ^.className := styleOf(classes.margin))(
"Custom CSS"
),
<.ThemeProvider(^.theme := {_: NativeTheme => theme})(
<.ThemeProvider(^.theme := nativeToTheme)(
<.Button(^.variant := "contained", ^.color := "primary", ^.className := styleOf(classes.margin))(
"Theme Provider"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import scommons.react._

object IconButtons extends FunctionComponent[Unit] {

private val useStyles = makeStyles(theme => {
private[button] val useStyles = makeStyles(theme => {
val s = new Styles {
val root = new Styles {
val `& > *` = new Styles {
Expand Down
Loading

0 comments on commit 16ed849

Please sign in to comment.