mirror of
https://github.com/rowtype-yoga/ry-blocks.git
synced 2024-11-08 23:07:08 +03:00
Mostly buttons
This commit is contained in:
parent
20e0552b77
commit
3c1f4dfab3
@ -4,11 +4,9 @@ import Prelude hiding (div)
|
||||
import Effect (Effect)
|
||||
import Effect.Unsafe (unsafePerformEffect)
|
||||
import React.Basic (JSX, element, fragment)
|
||||
import React.Basic.DOM (css)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.Emotion (str)
|
||||
import React.Basic.Emotion as E
|
||||
import React.Basic.Events (handler_)
|
||||
import Yoga (div, (/>), (</), (</>))
|
||||
import Yoga.Block as Block
|
||||
import Yoga.Block.Atom.Button.Types as ButtonType
|
||||
@ -40,23 +38,25 @@ button = do
|
||||
[ R.h1_ [ R.text "Button Examples" ]
|
||||
, R.h2_ [ R.text "Button types" ]
|
||||
, Block.cluster </ { space: "var(--s-1)" }
|
||||
/> [ div </ {}
|
||||
/> [ Button.component </ { buttonType: ButtonType.Generic } /> [ R.text "Generic" ]
|
||||
, Button.component </ { buttonType: ButtonType.Primary } /> [ R.text "Primary" ]
|
||||
]
|
||||
/> [ Button.component </ { buttonType: ButtonType.Generic } /> [ R.text "Generic" ]
|
||||
, Button.component </ { buttonType: ButtonType.Primary } /> [ R.text "Primary" ]
|
||||
, Button.component </ { buttonType: ButtonType.Dangerous } /> [ R.text "Dangerous" ]
|
||||
]
|
||||
, R.h2_ [ R.text "Button shapes" ]
|
||||
, Block.cluster </ { space: "var(--s-1)" }
|
||||
/> [ div </ {}
|
||||
/> [ Button.component </ { buttonType: ButtonType.Generic, buttonShape: ButtonType.Pill } /> [ R.text "Generic" ]
|
||||
, Button.component </ { buttonType: ButtonType.Primary, buttonShape: ButtonType.Pill } /> [ R.text "Primary" ]
|
||||
]
|
||||
/> [ Button.component </ { buttonType: ButtonType.Generic, buttonShape: ButtonType.Pill } /> [ R.text "Generic" ]
|
||||
, Button.component </ { buttonType: ButtonType.Primary, buttonShape: ButtonType.Pill } /> [ R.text "Primary" ]
|
||||
]
|
||||
, R.h2_ [ R.text "Icon button" ]
|
||||
, Block.cluster </ { space: "var(--s-1)" }
|
||||
/> [ div </ {}
|
||||
/> [ Button.component </ {} /> [ Block.icon </> { icon: Icon.questionMark, size: str "var(--s2)", colour: str colour.highlight } ]
|
||||
]
|
||||
/> [ Button.component </ {} /> [ Block.icon </> { icon: Icon.questionMark, size: str "var(--s2)", colour: str colour.highlight } ]
|
||||
]
|
||||
, R.h2_ [ R.text "Disabled" ]
|
||||
, Block.cluster </ { space: "var(--s-1)" }
|
||||
/> [ Button.component </ { buttonType: ButtonType.Generic, disabled: true } /> [ R.text "Generic" ]
|
||||
, Button.component </ { buttonType: ButtonType.Primary, disabled: true } /> [ R.text "Primary" ]
|
||||
, Button.component </ { buttonType: ButtonType.Generic, buttonShape: ButtonType.Pill, disabled: true } /> [ R.text "Generic" ]
|
||||
, Button.component </ { buttonType: ButtonType.Primary, buttonShape: ButtonType.Pill, disabled: true } /> [ R.text "Primary" ]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
@ -16,46 +16,14 @@ gradientBackground =
|
||||
colour.highlightDarker
|
||||
","
|
||||
colour.highlightLighter
|
||||
"),linear-gradient(225deg,"
|
||||
")"
|
||||
","
|
||||
"linear-gradient(225deg,"
|
||||
colour.highlightRotatedBackwards
|
||||
","
|
||||
colour.highlightRotatedForwards
|
||||
")"
|
||||
|
||||
buttonContainer ∷ Style
|
||||
buttonContainer =
|
||||
css
|
||||
{ background: str colour.interfaceBackground
|
||||
, boxShadow: str "0 1px 4px rgba(0,0,0,0.30)"
|
||||
, borderTop: str $ i "1px solid " colour.interfaceBackgroundHighlight
|
||||
, borderBottom: str $ i "1px solid " colour.interfaceBackgroundShadow
|
||||
, display: inlineFlex
|
||||
, padding: str "2px"
|
||||
, justifyContent: center
|
||||
, alignItems: center
|
||||
, borderRadius: var "--s-1"
|
||||
, """&[data-button-shape="pill"]""":
|
||||
nest
|
||||
{ borderRadius: var "--s1"
|
||||
, "& > button":
|
||||
nest
|
||||
{ padding: str "calc(var(--s-1) * 0.8) var(--s0)"
|
||||
}
|
||||
}
|
||||
, """&[data-button-type="primary"]""":
|
||||
nest
|
||||
{ background: gradientBackground
|
||||
, backgroundSize: str "200% 200%"
|
||||
, animation: backgroundAnimation <> str " alternate ease-out 10s infinite"
|
||||
, boxShadow: str "0 1px 4px 0px rgba(0,0,0,0.40)"
|
||||
, borderColor: str "transparent"
|
||||
, "& > button":
|
||||
nest
|
||||
{ color: str colour.highlightText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
backgroundAnimation ∷ StyleProperty
|
||||
backgroundAnimation =
|
||||
keyframes
|
||||
@ -66,15 +34,81 @@ backgroundAnimation =
|
||||
button ∷ Style
|
||||
button =
|
||||
css
|
||||
{ background: str "transparent"
|
||||
{ background: str colour.interfaceBackground
|
||||
, boxShadow: str "0 1px 4px rgba(0,0,0,0.30)"
|
||||
, border: str $ i "1px solid transparent"
|
||||
, borderTop: str $ i "1px solid " colour.interfaceBackgroundHighlight
|
||||
, borderBottom: str $ i "1px solid " colour.interfaceBackgroundShadow
|
||||
, display: inlineFlex
|
||||
, padding: str "calc(var(--s-1) * 0.85) var(--s0)"
|
||||
, justifyContent: center
|
||||
, alignItems: center
|
||||
, borderRadius: var "--s-1"
|
||||
, color: str colour.text
|
||||
, boxSizing: borderBox
|
||||
, fontSize: var "--s0"
|
||||
, fontFamily: var "--mainFont"
|
||||
, fontWeight: str "500"
|
||||
, letterSpacing: str "calc(var(--s-5)*0.2)"
|
||||
, padding: str "calc(var(--s-1) * 0.85) var(--s0)"
|
||||
, border: none
|
||||
, fontWeight: str "450"
|
||||
, letterSpacing: str "calc(var(--s-5)* (-0.1))"
|
||||
, userSelect: none
|
||||
, "&:focus": nest { outline: none }
|
||||
, transition: str "all 0.2s ease-out" <> str "transform 50ms ease-in"
|
||||
, """&[data-button-shape="pill"]""":
|
||||
nest
|
||||
{ borderRadius: str "calc(var(--s1) * 0.85)"
|
||||
, padding: str "calc(var(--s-1) * 0.9) var(--s0)"
|
||||
}
|
||||
, """&[data-button-type="primary"]""":
|
||||
nest
|
||||
{ background: gradientBackground
|
||||
, backgroundSize: str "200% 200%"
|
||||
, fontWeight: str "600"
|
||||
, letterSpacing: str "calc(var(--s-5)* (0.1))"
|
||||
, animation: backgroundAnimation <> str " alternate ease-out 10s infinite"
|
||||
, boxShadow: str "0 1px 4px 0px rgba(0,0,0,0.40)"
|
||||
, borderColor: str "transparent"
|
||||
, color: str colour.highlightText
|
||||
, """&:focus-visible""":
|
||||
nest
|
||||
{ borderColor: str $ colour.background0
|
||||
}
|
||||
, """&:active""":
|
||||
nest
|
||||
{ boxShadow: str "inset 0 1px 6px rgba(0,0,0,0.40)"
|
||||
, border: str $ i "1px solid transparent"
|
||||
}
|
||||
, "&:disabled":
|
||||
nest
|
||||
{ background: str colour.highlightDisabled
|
||||
}
|
||||
}
|
||||
, """&[data-button-type="dangerous"]""":
|
||||
nest
|
||||
{ color: str $ colour.interfaceDangerousText
|
||||
, background: str $ colour.interfaceBackgroundDangerous
|
||||
, fontWeight: str "600"
|
||||
, letterSpacing: str "calc(var(--s-5) * -0.10)"
|
||||
}
|
||||
, """&:focus""": nest { outline: none }
|
||||
, """&:focus-visible""":
|
||||
nest
|
||||
{ boxShadow: str $ "0 0 0 var(--s-4) " <> colour.highlight
|
||||
}
|
||||
, """&:active""":
|
||||
nest
|
||||
{ boxShadow:
|
||||
str
|
||||
$ "inset 0 1px var(--s-1) rgba(0,0,0,0.20)"
|
||||
, borderTop: str $ i "1px solid " colour.interfaceBackgroundShadow
|
||||
, borderBottom: str $ i "1px solid " colour.interfaceBackgroundShadow
|
||||
, transform: str "scale3d(0.95,0.95,0.95)"
|
||||
, transition: str "transform 50ms ease"
|
||||
}
|
||||
, "&:disabled":
|
||||
nest
|
||||
{ color: str colour.interfaceTextDisabled
|
||||
, boxShadow: none
|
||||
, background: str colour.interfaceBackgroundDisabled
|
||||
, borderTop: str $ i "1px solid " colour.interfaceBackgroundShadow
|
||||
, borderBottom: str $ i "1px solid " colour.interfaceBackgroundShadow
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import Prelude
|
||||
|
||||
data ButtonType
|
||||
= Primary
|
||||
| Dangerous
|
||||
| Generic
|
||||
|
||||
derive instance eqButtonType ∷ Eq ButtonType
|
||||
@ -12,6 +13,7 @@ renderButtonType ∷ ButtonType -> String
|
||||
renderButtonType = case _ of
|
||||
Primary -> "primary"
|
||||
Generic -> "generic"
|
||||
Dangerous -> "dangerous"
|
||||
|
||||
data ButtonShape
|
||||
= Rounded
|
||||
|
@ -36,14 +36,10 @@ rawComponent =
|
||||
{ "button-type": renderButtonType (props.buttonType ?|| Button.Generic)
|
||||
, "button-shape": renderButtonShape (props.buttonShape ?|| Button.Rounded)
|
||||
}
|
||||
pure $ div
|
||||
</* { css: Style.buttonContainer
|
||||
, className: "ry-button-container"
|
||||
, _data
|
||||
}
|
||||
/> [ emotionButton propsRef
|
||||
props
|
||||
{ className: "ry-button"
|
||||
, css: Style.button
|
||||
}
|
||||
]
|
||||
pure
|
||||
$ emotionButton propsRef
|
||||
props
|
||||
{ className: "ry-button"
|
||||
, css: Style.button
|
||||
, _data
|
||||
}
|
||||
|
@ -22,9 +22,20 @@ span props =
|
||||
, display: inlineFlex
|
||||
, justifyContent: center
|
||||
, alignItems: center
|
||||
, margin: _0
|
||||
, padding: _0
|
||||
, width
|
||||
, height
|
||||
, overflow: hidden
|
||||
, "& > svg":
|
||||
nest
|
||||
{ width: (props.width <|> props.size) ?|| (str "auto")
|
||||
, height: (props.height <|> props.size) ?|| (str "1.2ch")
|
||||
{ width
|
||||
, height
|
||||
, margin: _0
|
||||
, padding: _0
|
||||
}
|
||||
}
|
||||
where
|
||||
width = (props.width <|> props.size) ?|| (str "auto")
|
||||
|
||||
height = (props.height <|> props.size) ?|| (str "1ch")
|
||||
|
@ -10,7 +10,7 @@ import React.Basic (JSX, element, fragment)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.Emotion as E
|
||||
import React.Basic.Events (handler_)
|
||||
import Yoga (el)
|
||||
import Yoga (el, (</), (/>), (</>))
|
||||
import Yoga.Block as Block
|
||||
import Yoga.Block.Atom.Input as Input
|
||||
import Yoga.Block.Atom.Input.Types as HTMLInput
|
||||
@ -38,7 +38,7 @@ input = do
|
||||
[ R.div_
|
||||
[ R.h1_ [ R.text "Input Examples" ]
|
||||
, R.h2_ [ R.text "Generic Input" ]
|
||||
, element Input.component { value: "A Generic Input", onChange: handler_ mempty }
|
||||
, Input.component </> { value: "A Generic Input", onChange: handler_ mempty }
|
||||
, R.h2_ [ R.text "Validation on text Input" ]
|
||||
, element Input.component { type: HTMLInput.Text, label: nes (SProxy ∷ _ "Is undefined a function?"), value: "Yes, why not?", onChange: handler_ mempty, _aria: Object.singleton "invalid" "true" }
|
||||
, element Input.component { type: HTMLInput.Text, label: nes (SProxy ∷ _ "What's the type of null?"), value: "object", onChange: handler_ mempty, _aria: Object.singleton "invalid" "false" }
|
||||
@ -49,17 +49,15 @@ input = do
|
||||
, _aria: Object.singleton "required" "true"
|
||||
}
|
||||
, R.h3_ [ R.text "With a label" ]
|
||||
, el Block.cluster {}
|
||||
[ el R.form' {}
|
||||
[ element Input.component { label: nes (SProxy ∷ _ "This has a label"), value: "And text", onChange: handler_ mempty }
|
||||
, element Input.component { label: nes (SProxy ∷ _ "This has a label"), value: "", onChange: handler_ mempty }
|
||||
, element Input.component { label: nes (SProxy ∷ _ "This has a label"), placeholder: "A very long placeholder, too..." }
|
||||
, element Input.component { label: nes (SProxy ∷ _ "Pig nose"), leading: R.text "🐽🤣" }
|
||||
, element Input.component { label: nes (SProxy ∷ _ "Pig nose"), trailing: R.text "🤫" }
|
||||
, element Input.component { label: nes (SProxy ∷ _ "Pig nose"), leading: R.text "🌭" }
|
||||
, element Input.component { label: nes (SProxy ∷ _ "Pig nose"), leading: R.text "⭐", trailing: R.text "🔮" }
|
||||
]
|
||||
]
|
||||
, Block.cluster </ {}
|
||||
/> [ element Input.component { label: nes (SProxy ∷ _ "This has a label"), value: "And text", onChange: handler_ mempty }
|
||||
, element Input.component { label: nes (SProxy ∷ _ "This has a label"), value: "", onChange: handler_ mempty }
|
||||
, element Input.component { label: nes (SProxy ∷ _ "This has a label"), placeholder: "A very long placeholder, too..." }
|
||||
, element Input.component { label: nes (SProxy ∷ _ "Pig nose"), leading: R.text "🐽🤣" }
|
||||
, element Input.component { label: nes (SProxy ∷ _ "Pig nose"), trailing: R.text "🤫" }
|
||||
, element Input.component { label: nes (SProxy ∷ _ "Pig nose"), leading: R.text "🌭" }
|
||||
, element Input.component { label: nes (SProxy ∷ _ "Pig nose"), leading: R.text "⭐", trailing: R.text "🔮" }
|
||||
]
|
||||
, R.h2_ [ R.text "[BUG] Overflowing label" ]
|
||||
, element Input.component
|
||||
{ type: HTMLInput.Text
|
||||
|
@ -43,6 +43,7 @@ labelContainer ∷ Style
|
||||
labelContainer =
|
||||
css
|
||||
{ position: absolute
|
||||
, overflow: visible
|
||||
, top: _0
|
||||
, left: _0
|
||||
, display: inlineBlock
|
||||
@ -147,13 +148,14 @@ leftIconContainer =
|
||||
}
|
||||
}
|
||||
|
||||
inputWrapper ∷ ∀ r. { | Props OptionalProp r } -> Style
|
||||
inputWrapper props =
|
||||
inputWrapper ∷ Style
|
||||
inputWrapper =
|
||||
css
|
||||
{ position: relative
|
||||
, boxSizing: borderBox
|
||||
, backgroundColor: str colour.inputBackground
|
||||
, display: inlineFlex
|
||||
, display: flex
|
||||
, minWidth: str "calc(var(--s4) *2 )"
|
||||
, "--left-icon-size": var "--s0"
|
||||
, "--right-icon-size": str "calc(var(--s0) * 1.2)"
|
||||
, "--input-border-radius": var "--s-1"
|
||||
@ -161,7 +163,7 @@ inputWrapper props =
|
||||
, "--input-top-padding": var "--s-5"
|
||||
, "--input-bottom-padding": var "--s-5"
|
||||
, alignItems: center
|
||||
, justifyContent: flexStart
|
||||
, justifyContent: center
|
||||
, paddingLeft: str "calc(var(--input-side-padding) - var(--border-width))"
|
||||
, paddingRight: str "calc(var(--input-side-padding) - var(--border-width))"
|
||||
, paddingTop: str "calc(var(--input-top-padding) - var(--border-width))"
|
||||
@ -173,26 +175,28 @@ inputWrapper props =
|
||||
, """&[data-invalid="false"]""":
|
||||
nest
|
||||
{ borderColor: str colour.success
|
||||
, "--border-width": str "var(--s-5)"
|
||||
}
|
||||
, """&[data-invalid="true"]""":
|
||||
nest
|
||||
{ borderColor: str colour.invalid
|
||||
, "--border-width": str "var(--s-5)"
|
||||
}
|
||||
, "&:focus-within":
|
||||
nest
|
||||
{ "--border-width": str "var(--s-5)"
|
||||
, borderColor: str colour.highlight
|
||||
, transition: str "border-color 0s linear 0.1s"
|
||||
}
|
||||
}
|
||||
|
||||
input ∷ ∀ r. { | Props OptionalProp r } -> Style
|
||||
input props =
|
||||
input ∷ Style
|
||||
input =
|
||||
css
|
||||
{ "&[type=text],&[type=search],&[type=password],&[type=number],&:not([type])":
|
||||
nest
|
||||
{ color: str colour.text
|
||||
, width: _100percent
|
||||
, flex: str "1"
|
||||
, flex: str "2"
|
||||
, "--padding-top": var "--s-1"
|
||||
, "--padding-bottom": var "--s-1"
|
||||
, "&[aria-labelledby]":
|
||||
@ -221,12 +225,4 @@ input props =
|
||||
nest
|
||||
{ outline: none
|
||||
}
|
||||
, "&[type=button], &[type=submit]":
|
||||
nest
|
||||
{ background: str colour.highlight
|
||||
, color: str "white"
|
||||
, boxShadow: str "0 1px 4px rgba(0,0,0,0.5)"
|
||||
, borderColour: str colour.highlight
|
||||
, height: str "auto"
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,9 @@ module Yoga.Block.Atom.Input.View where
|
||||
import Yoga.Prelude.View
|
||||
import Data.Array as Array
|
||||
import Data.Interpolate (i)
|
||||
import Data.Semigroup.Foldable (intercalateMap)
|
||||
import Data.String.NonEmpty (NonEmptyString)
|
||||
import Data.String.NonEmpty as NonEmptyString
|
||||
import Data.Symbol (SProxy(..))
|
||||
import Debug.Trace (spy)
|
||||
import Foreign.Object (Object)
|
||||
import Foreign.Object as Object
|
||||
import Framer.Motion as M
|
||||
@ -21,7 +19,6 @@ import Yoga.Block.Atom.Input.Style as Style
|
||||
import Yoga.Block.Atom.Input.Types (HTMLInput)
|
||||
import Yoga.Block.Atom.Input.Types as HTMLInput
|
||||
import Yoga.Block.Icon.SVG as SVGIcon
|
||||
import Yoga.Block.Internal.OptionalProp (asMaybe)
|
||||
|
||||
type PropsF f =
|
||||
( leading ∷ f JSX
|
||||
@ -60,16 +57,16 @@ containerVariants =
|
||||
{ focussed:
|
||||
css
|
||||
{ clipPath
|
||||
, transition: { duration: 1.3 }
|
||||
, transition: { duration: 0.7 }
|
||||
}
|
||||
, blurred:
|
||||
css
|
||||
{ clipPath:
|
||||
drawPathUntil (Array.length path) path
|
||||
drawPathUntil (Array.length path + 1) path
|
||||
}
|
||||
}
|
||||
where
|
||||
clipPath = 3 Array... (Array.length path / 2 + 1) <#> \ln -> drawPathUntil (ln * 2) path
|
||||
clipPath = 6 Array... (Array.length path) <#> \ln -> drawPathUntil ln path
|
||||
|
||||
type Point =
|
||||
{ x ∷ Int, y ∷ Int }
|
||||
@ -83,28 +80,27 @@ drawPathUntil idx thePath = do
|
||||
let firstFew = Array.take idx thePath
|
||||
let lastFew = Array.drop idx thePath $> (Array.last firstFew # fromMaybe' \_ -> unsafeCrashWith "ogod")
|
||||
let rendered = intercalate "," $ fn <$> (firstFew <> lastFew)
|
||||
spy "polybius" $ i "polygon(" rendered ")"
|
||||
i "polygon(" rendered ")"
|
||||
|
||||
path ∷ Array Point
|
||||
path = mkPath 5
|
||||
path = mkPath 3 7
|
||||
|
||||
mkPath ∷ Int -> Array Point
|
||||
mkPath d = do
|
||||
mkPath ∷ Int -> Int -> Array Point
|
||||
mkPath borderX borderY = do
|
||||
let
|
||||
inside =
|
||||
[ p d d
|
||||
, p (100 - d) d
|
||||
, p (100 - d) (100 - d)
|
||||
, p d (100 - d)
|
||||
, p d d
|
||||
[ {- ⌜ -} p borderX borderY
|
||||
, {- ⌞ -} p borderX (100 - borderY)
|
||||
, {- ⌟ -} p (100 - borderX) (100 - borderY)
|
||||
, {- ⌝ -} p (100 - borderX) borderY
|
||||
, {- ⌜ -} p borderX borderY
|
||||
]
|
||||
outside =
|
||||
[ p d 0
|
||||
, p 100 0
|
||||
, p 100 100
|
||||
, p 0 100
|
||||
, p 0 0
|
||||
, p d 0 -- one turn, starting way back
|
||||
[ {- ⌜ -} p 0 0
|
||||
, {- ⌞ -} p 0 100
|
||||
, {- ⌟ -} p 100 100
|
||||
, {- ⌝ -} p 100 0
|
||||
, {- ⌜ -} p 0 0
|
||||
]
|
||||
inside <> outside <> (Array.reverse inside)
|
||||
|
||||
@ -216,7 +212,7 @@ rawComponent =
|
||||
, animate: M.animate if hasFocus then containerVariantLabels.focussed else containerVariantLabels.blurred
|
||||
}
|
||||
{ className: "ry-input-wrapper"
|
||||
, css: Style.inputWrapper props
|
||||
, css: Style.inputWrapper
|
||||
, _data:
|
||||
Object.fromHomogeneous
|
||||
{ "invalid": aria # Object.lookup "invalid" # fromMaybe ""
|
||||
@ -230,7 +226,7 @@ rawComponent =
|
||||
# setOrDelete (SProxy ∷ _ "value") (maybeValue # maybeToOp)
|
||||
)
|
||||
{ className: "ry-input"
|
||||
, css: Style.input props
|
||||
, css: Style.input
|
||||
, onFocus: composeHandler props.onFocus onFocus
|
||||
, onBlur: composeHandler props.onBlur onBlur
|
||||
, _aria:
|
||||
@ -303,14 +299,14 @@ password =
|
||||
pure
|
||||
$ div
|
||||
</* { className: "ry-input-wrapper"
|
||||
, css: Style.inputWrapper props
|
||||
, css: Style.inputWrapper
|
||||
}
|
||||
/> [ leading
|
||||
, emotionInput
|
||||
ref
|
||||
props { type = HTMLInput.toString <$> props.type # unsafeUnOptional }
|
||||
{ className: "ry-input"
|
||||
, css: Style.input props
|
||||
, css: Style.input
|
||||
, type: if hidePassword then "password" else "text"
|
||||
}
|
||||
, trailing
|
||||
|
@ -18,6 +18,7 @@ import React.Basic (JSX, ReactComponent, element, elementKeyed, fragment)
|
||||
import React.Basic.DOM (CSS, css)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.DOM.Events (targetValue)
|
||||
import React.Basic.Emotion (str)
|
||||
import React.Basic.Emotion as E
|
||||
import React.Basic.Events (handler, handler_)
|
||||
import React.Basic.Hooks (reactComponent)
|
||||
@ -27,11 +28,16 @@ import React.Basic.Popper.Placement.Types as Placement
|
||||
import React.Basic.Popper.Types (nullRef)
|
||||
import Unsafe.Coerce (unsafeCoerce)
|
||||
import Yoga ((/>), (</), (</>))
|
||||
import Yoga.Block as Block
|
||||
import Yoga.Block.Atom.Icon as Icon
|
||||
import Yoga.Block.Atom.Input as Input
|
||||
import Yoga.Block.Atom.Input.Types as HTMLInput
|
||||
import Yoga.Block.Atom.Popover as Popover
|
||||
import Yoga.Block.Container.Style (colour)
|
||||
import Yoga.Block.Container.Style as Styles
|
||||
import Yoga.Block.Icon.SVG as Icons
|
||||
import Yoga.Block.Layout.Box as Box
|
||||
import Yoga.Block.Layout.Cluster as Cluster
|
||||
import Yoga.Block.Layout.Stack as Stack
|
||||
|
||||
default ∷
|
||||
@ -67,20 +73,47 @@ popover = do
|
||||
reactComponent "PopoverExample" \props -> React.do
|
||||
referenceElement /\ setReferenceElement <- React.useState' nullRef
|
||||
text /\ setText <- React.useState' ""
|
||||
visible /\ setVisible <- React.useState' false
|
||||
visible /\ setVisible <- React.useState' true
|
||||
selectedAuthors /\ modSelectedAuthors <-
|
||||
React.useState [ "William Shakespeare", "Agatha Christie" ]
|
||||
let
|
||||
matchingAuthors =
|
||||
authors
|
||||
# (_ Array.\\ selectedAuthors)
|
||||
# Array.filter
|
||||
( \a ->
|
||||
String.contains (String.Pattern (String.toLower text))
|
||||
(String.toLower a)
|
||||
)
|
||||
let
|
||||
inputWrapper =
|
||||
R.div'
|
||||
</ { ref: unsafeCoerce (mkEffectFn1 setReferenceElement)
|
||||
}
|
||||
inputWrapper = R.div' </ { ref: unsafeCoerce (mkEffectFn1 setReferenceElement) }
|
||||
pill t =
|
||||
Block.box </ { padding: str "var(--s-3)" }
|
||||
/> [ Block.cluster
|
||||
</ { style:
|
||||
css
|
||||
{ background: colour.highlight
|
||||
, fontSize: "var(--s-1)"
|
||||
, space: "var(--s-5)"
|
||||
, borderRadius: "var(--s-2)"
|
||||
}
|
||||
}
|
||||
/> [ R.text t
|
||||
, Block.centre
|
||||
</ { style:
|
||||
css
|
||||
{ background: "hotpink"
|
||||
}
|
||||
, andText: true
|
||||
}
|
||||
/> [ Icon.component
|
||||
</> { icon: Icons.cross, size: str "var(--s-1)"
|
||||
}
|
||||
]
|
||||
]
|
||||
]
|
||||
pills = pill <$> selectedAuthors
|
||||
leading = Block.cluster </ {} /> pills
|
||||
input =
|
||||
Input.component
|
||||
</> { id: "author"
|
||||
@ -92,19 +125,20 @@ popover = do
|
||||
, onChange: handler targetValue $ traverse_ setText
|
||||
, onBlur: handler_ (setVisible false)
|
||||
, onFocus: handler_ (setVisible true)
|
||||
, trailing: R.text "▼"
|
||||
, leading
|
||||
, autoComplete: "off"
|
||||
}
|
||||
pop children =
|
||||
elementKeyed motionPopover
|
||||
$ Motion.motion
|
||||
{ initial:
|
||||
css { clipPath: "polygon(0% 0%, 100% 0%, 100% 0%, 0% 0%)" }
|
||||
css { maxHeight: 30, opacity: 0.0 }
|
||||
, exit:
|
||||
css { clipPath: "polygon(0% 0%, 100% 0%, 100% 0%, 0% 0%)" }
|
||||
css { maxHeight: 30, opacity: 0.0 }
|
||||
, animate:
|
||||
css
|
||||
{ clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)"
|
||||
{ maxHeight: 400
|
||||
, opacity: 1
|
||||
}
|
||||
, transition:
|
||||
Motion.transition
|
||||
@ -120,9 +154,10 @@ popover = do
|
||||
, style:
|
||||
css
|
||||
{ boxShadow: "0px 9px 12px rgba(40,40,40,0.5)"
|
||||
, background: "rgba(50,50,70, 0.7)"
|
||||
, background: colour.interfaceBackground
|
||||
, borderRadius: "9px"
|
||||
, borderTop: "solid 1px rgba(80,80,100,1.0)"
|
||||
, borderTop: "solid 1px " <> colour.interfaceBackgroundHighlight
|
||||
, borderBottom: "solid 1px " <> colour.interfaceBackgroundShadow
|
||||
, overflowY: "scroll"
|
||||
, maxHeight: "400px"
|
||||
, width: "300px"
|
||||
@ -149,6 +184,7 @@ popover = do
|
||||
</ { key: a
|
||||
-- , layout: Motion.layout true
|
||||
-- , variants: Motion.variants itemVariants
|
||||
, onClick: handler_ (modSelectedAuthors (_ `Array.snoc` a))
|
||||
}
|
||||
/> [ R.text a ]
|
||||
pure
|
||||
|
@ -22,29 +22,25 @@ container =
|
||||
[ R.text "Content"
|
||||
, el Stack.component {}
|
||||
[ el Cluster.component {}
|
||||
[ R.div_
|
||||
[ R.input { value: "Text" }
|
||||
, R.input { type: "number", value: "0" }
|
||||
, styledLeaf R.input'
|
||||
{ className: "styledinput"
|
||||
, css: inputFocus
|
||||
, value: "focus"
|
||||
}
|
||||
, R.input
|
||||
{ className: "styledinput"
|
||||
, value: "focus"
|
||||
, disabled: true
|
||||
}
|
||||
]
|
||||
[ R.input { value: "Text" }
|
||||
, R.input { type: "number", value: "0" }
|
||||
, styledLeaf R.input'
|
||||
{ className: "styledinput"
|
||||
, css: inputFocus
|
||||
, value: "focus"
|
||||
}
|
||||
, R.input
|
||||
{ className: "styledinput"
|
||||
, value: "focus"
|
||||
, disabled: true
|
||||
}
|
||||
]
|
||||
, R.input { type: "file" }
|
||||
, el Cluster.component {}
|
||||
[ R.div_
|
||||
[ R.input { type: "checkbox" }
|
||||
, R.input { type: "checkbox", checked: true }
|
||||
, R.input { type: "radio" }
|
||||
, R.input { type: "radio", checked: true }
|
||||
]
|
||||
[ R.input { type: "checkbox" }
|
||||
, R.input { type: "checkbox", checked: true }
|
||||
, R.input { type: "radio" }
|
||||
, R.input { type: "radio", checked: true }
|
||||
]
|
||||
, R.input { type: "range" }
|
||||
]
|
||||
|
@ -131,9 +131,13 @@ defaultColours =
|
||||
, invalid
|
||||
, invalidText
|
||||
, required
|
||||
, interfaceBackground: lightBg
|
||||
, interfaceTextDisabled: darken 0.33 lightBg
|
||||
, interfaceBackground
|
||||
, interfaceBackgroundDangerous
|
||||
, interfaceDangerousText
|
||||
, interfaceBackgroundDisabled: darken 0.03 lightBg
|
||||
, interfaceTextDisabled: darken 0.30 lightBg
|
||||
, interfaceBackgroundHighlight: lighten 0.05 lightBg
|
||||
, highlightDisabled: (desaturate 0.80 >>> lighten 0.28) highlight
|
||||
, interfaceBackgroundShadow: darken 0.04 lightBg
|
||||
, inputBackground: lightBg
|
||||
, inputBorder: darken 0.1 lightBg
|
||||
@ -167,17 +171,21 @@ defaultColours =
|
||||
, textInverted: darkBg
|
||||
, backgroundInverted: lightBg
|
||||
, interfaceBackground: interfaceBackgroundDark
|
||||
, interfaceTextDisabled: lighten 0.8 darkBg
|
||||
, interfaceBackgroundDangerous: interfaceBackgroundDangerousDark
|
||||
, interfaceDangerousText: interfaceDangerousTextDark
|
||||
, interfaceBackgroundDisabled: darken 0.3 interfaceBackgroundDark
|
||||
, interfaceTextDisabled: (desaturate 0.3 >>> lighten 0.25) interfaceBackgroundDark
|
||||
, interfaceBackgroundHighlight: lighten 0.1 interfaceBackgroundDark
|
||||
, interfaceBackgroundShadow: darken 0.1 interfaceBackgroundDark
|
||||
, inputBackground: darkBg
|
||||
, inputBorder: lighten 0.17 darkBg
|
||||
, success
|
||||
, success: successDark
|
||||
, successText
|
||||
, required
|
||||
, invalid
|
||||
, invalidText
|
||||
, highlight: highlightDark
|
||||
, highlightDisabled: (desaturate 0.76 >>> darken 0.32) highlightDark
|
||||
, highlightLighter: withAlpha 0.2 (Color.lighten 0.5 highlightDark)
|
||||
, highlightDarker: withAlpha 0.4 (Color.darken 0.5 highlightDark)
|
||||
, highlightRotatedForwards: highlightDark # rotateHue 30.0
|
||||
@ -194,9 +202,21 @@ defaultColours =
|
||||
|
||||
interfaceBackgroundDark = Color.hsl 240.0 0.10 0.33
|
||||
|
||||
interfaceBackground = lightBg
|
||||
|
||||
interfaceBackgroundDangerous = interfaceBackground
|
||||
|
||||
interfaceDangerousText = invalid
|
||||
|
||||
interfaceBackgroundDangerousDark = Color.hsl 340.0 0.55 0.30
|
||||
|
||||
interfaceDangerousTextDark = Color.hsl 340.0 1.0 0.90
|
||||
|
||||
highlightText = Color.rgb 0xFF 0xFF 0xFF
|
||||
|
||||
success = Color.rgb 20 200 60
|
||||
success = Color.rgb 10 150 25
|
||||
|
||||
successDark = Color.rgb 20 200 60
|
||||
|
||||
successText = Color.rgb 250 250 250
|
||||
|
||||
@ -232,6 +252,9 @@ type FlatTheme a =
|
||||
, background100 ∷ a
|
||||
, backgroundInverted ∷ a
|
||||
, interfaceBackground ∷ a
|
||||
, interfaceBackgroundDangerous ∷ a
|
||||
, interfaceDangerousText ∷ a
|
||||
, interfaceBackgroundDisabled ∷ a
|
||||
, interfaceTextDisabled ∷ a
|
||||
, interfaceBackgroundHighlight ∷ a
|
||||
, interfaceBackgroundShadow ∷ a
|
||||
@ -242,6 +265,7 @@ type FlatTheme a =
|
||||
, highlightRotatedForwards ∷ a
|
||||
, highlightDarker ∷ a
|
||||
, highlightLighter ∷ a
|
||||
, highlightDisabled ∷ a
|
||||
, highlightText ∷ a
|
||||
, success ∷ a
|
||||
, successText ∷ a
|
||||
|
21
src/Yoga/Block/Icon/SVG/Cross.purs
Normal file
21
src/Yoga/Block/Icon/SVG/Cross.purs
Normal file
@ -0,0 +1,21 @@
|
||||
module Yoga.Block.Icon.SVG.Cross where
|
||||
|
||||
import React.Basic (JSX)
|
||||
import React.Basic.DOM.SVG as SVG
|
||||
|
||||
cross ∷ JSX
|
||||
cross =
|
||||
SVG.svg
|
||||
{ viewBox: "0 0 100 100"
|
||||
, xmlns: "http://www.w3.org/2000/svg"
|
||||
, fillRule: "evenodd"
|
||||
, clipRule: "evenodd"
|
||||
, strokeLinejoin: "round"
|
||||
, strokeMiterlimit: "2"
|
||||
, children:
|
||||
[ SVG.path
|
||||
{ d: "M50 2.339c26.305 0 47.661 21.356 47.661 47.661S76.305 97.661 50 97.661 2.339 76.305 2.339 50 23.695 2.339 50 2.339zm0 38.773L31.838 22.949l-8.889 8.889L41.112 50 22.949 68.162l8.889 8.889L50 58.888l18.162 18.163 8.889-8.889L58.888 50l18.163-18.162-8.889-8.889L50 41.112z"
|
||||
, fill: "var(--stroke-colour)"
|
||||
}
|
||||
]
|
||||
}
|
@ -7,6 +7,7 @@ module Yoga.Block.Icon.SVG
|
||||
, module Yoga.Block.Icon.SVG.Key
|
||||
, module Yoga.Block.Icon.SVG.SimpleKey
|
||||
, module Yoga.Block.Icon.SVG.QuestionMark
|
||||
, module Yoga.Block.Icon.SVG.Cross
|
||||
) where
|
||||
|
||||
import Yoga.Block.Icon.SVG.On (on)
|
||||
@ -17,3 +18,4 @@ import Yoga.Block.Icon.SVG.EyeOpen (eyeOpen)
|
||||
import Yoga.Block.Icon.SVG.Key (key)
|
||||
import Yoga.Block.Icon.SVG.SimpleKey (simpleKey)
|
||||
import Yoga.Block.Icon.SVG.QuestionMark (questionMark)
|
||||
import Yoga.Block.Icon.SVG.Cross (cross)
|
||||
|
25
src/Yoga/Block/Icon/SVG/Warn.purs
Normal file
25
src/Yoga/Block/Icon/SVG/Warn.purs
Normal file
@ -0,0 +1,25 @@
|
||||
module Yoga.Block.Icon.SVG.Warn where
|
||||
|
||||
import React.Basic (JSX)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.DOM.SVG as SVG
|
||||
|
||||
warn :: JSX
|
||||
warn = SVG.svg
|
||||
{ viewBox: "0 0 100 100"
|
||||
, xmlns: "http://www.w3.org/2000/svg"
|
||||
, fillRule: "evenodd"
|
||||
, clipRule: "evenodd"
|
||||
, strokeLinejoin: "round"
|
||||
, strokeMiterlimit: "2"
|
||||
, children:
|
||||
[ SVG.path
|
||||
{ fill: "none"
|
||||
, d: "M0 0h100v100H0z"
|
||||
}
|
||||
, SVG.path
|
||||
{ d: "M41.478 15.313a9.704 9.704 0 0117.044 0L91.27 75.397a9.706 9.706 0 01-8.522 14.351H17.252A9.705 9.705 0 018.73 75.397l32.748-60.084zM50 77.357c2.909 0 5.432-2.432 5.455-5.455-.023-2.977-2.546-5.409-5.455-5.409-3 0-5.477 2.432-5.454 5.409C44.523 74.925 47 77.357 50 77.357zm5.046-44.137H44.932l.909 29.591h8.318l.887-29.591z"
|
||||
, fill: "#333"
|
||||
}
|
||||
]
|
||||
}
|
1
src/Yoga/Block/Icon/SVG/cross.svg
Normal file
1
src/Yoga/Block/Icon/SVG/cross.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2"><path fill="none" d="M0 0h100v100H0z"/><path d="M50 2.339c26.305 0 47.661 21.356 47.661 47.661S76.305 97.661 50 97.661 2.339 76.305 2.339 50 23.695 2.339 50 2.339zm0 38.773L31.838 22.949l-8.889 8.889L41.112 50 22.949 68.162l8.889 8.889L50 58.888l18.162 18.163 8.889-8.889L58.888 50l18.163-18.162-8.889-8.889L50 41.112z" fill="#333"/></svg>
|
After Width: | Height: | Size: 487 B |
1
src/Yoga/Block/Icon/SVG/warn.svg
Normal file
1
src/Yoga/Block/Icon/SVG/warn.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2"><path fill="none" d="M0 0h100v100H0z"/><path d="M41.478 15.313a9.704 9.704 0 0117.044 0L91.27 75.397a9.706 9.706 0 01-8.522 14.351H17.252A9.705 9.705 0 018.73 75.397l32.748-60.084zM50 77.357c2.909 0 5.432-2.432 5.455-5.455-.023-2.977-2.546-5.409-5.455-5.409-3 0-5.477 2.432-5.454 5.409C44.523 74.925 47 77.357 50 77.357zm5.046-44.137H44.932l.909 29.591h8.318l.887-29.591z" fill="#333"/></svg>
|
After Width: | Height: | Size: 540 B |
@ -36,15 +36,13 @@ cluster =
|
||||
, el Cluster.component
|
||||
{ style: css { backgroundColor: "hotpink" }
|
||||
}
|
||||
[ R.div_
|
||||
$ [ power
|
||||
( R.div
|
||||
{ children: [ R.text "Content" ]
|
||||
, style: css { backgroundColor: "teal" }
|
||||
}
|
||||
)
|
||||
30
|
||||
]
|
||||
[ power
|
||||
( R.div
|
||||
{ children: [ R.text "Content" ]
|
||||
, style: css { backgroundColor: "teal" }
|
||||
}
|
||||
)
|
||||
30
|
||||
]
|
||||
, R.h2_ [ R.text "Zero Space" ]
|
||||
, el Cluster.component
|
||||
@ -52,10 +50,8 @@ cluster =
|
||||
, space: "0"
|
||||
, justify: "flex-end"
|
||||
}
|
||||
[ R.div_
|
||||
[ R.div { children: [ R.text "Child 1" ], style: css { backgroundColor: "teal" } }
|
||||
, R.div { children: [ R.text "Child 2" ], style: css { backgroundColor: "rebeccapurple" } }
|
||||
]
|
||||
[ R.div { children: [ R.text "Child 1" ], style: css { backgroundColor: "teal" } }
|
||||
, R.div { children: [ R.text "Child 2" ], style: css { backgroundColor: "rebeccapurple" } }
|
||||
]
|
||||
]
|
||||
]
|
||||
|
@ -1,6 +1,7 @@
|
||||
module Yoga.Block.Layout.Cluster.View (component, Props, PropsF) where
|
||||
|
||||
import Yoga.Prelude.View
|
||||
import React.Basic.DOM as R
|
||||
import Yoga.Block.Layout.Cluster.Style as Style
|
||||
|
||||
type PropsF f =
|
||||
@ -25,4 +26,5 @@ rawComponent =
|
||||
$ emotionDiv ref props
|
||||
{ className: "ry-cluster " <>? props.className
|
||||
, css: Style.cluster props
|
||||
, children: [ R.div' </ {} /> props.children ]
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import React.Basic.DOM as R
|
||||
spec ∷ Spec Unit
|
||||
spec =
|
||||
after_ cleanup do
|
||||
describe "The cluster" do
|
||||
describe "The switcher" do
|
||||
it "renders without errors" do
|
||||
void
|
||||
$ renderComponent Switcher.component {}
|
||||
|
Loading…
Reference in New Issue
Block a user