mirror of
https://github.com/rowtype-yoga/ry-blocks.git
synced 2024-11-08 23:07:08 +03:00
Fix test
This commit is contained in:
parent
cbfdcbf46a
commit
d0bb8baf48
130
src/Yoga/Block/Atom/Input/View/Container.purs
Normal file
130
src/Yoga/Block/Atom/Input/View/Container.purs
Normal file
@ -0,0 +1,130 @@
|
||||
module Yoga.Block.Atom.Input.View.Container where
|
||||
|
||||
import Yoga.Prelude.View
|
||||
import Data.Array as Array
|
||||
import Data.Interpolate (i)
|
||||
import Foreign.Object as Object
|
||||
import Framer.Motion as M
|
||||
import Partial.Unsafe (unsafeCrashWith)
|
||||
import React.Basic.DOM (CSS, css)
|
||||
import React.Basic.Emotion (Style)
|
||||
import Yoga.Block.Atom.Input.Style as Style
|
||||
|
||||
type PropsF f =
|
||||
( css ∷ f Style
|
||||
, isInvalid ∷ f Boolean
|
||||
| Style.Props f (MandatoryProps ())
|
||||
)
|
||||
|
||||
type MandatoryProps r =
|
||||
( children ∷ Array JSX
|
||||
, hasFocus ∷ Boolean
|
||||
| r
|
||||
)
|
||||
|
||||
type Props =
|
||||
PropsF Id
|
||||
|
||||
type PropsOptional =
|
||||
PropsF OptionalProp
|
||||
|
||||
component ∷ ∀ p q. Union p q Props => ReactComponent { | MandatoryProps p }
|
||||
component = rawContainer
|
||||
|
||||
type Propski =
|
||||
{ css ∷ OptionalProp Style
|
||||
, hasFocus ∷ Boolean
|
||||
, isInvalid ∷ OptionalProp Boolean
|
||||
, children ∷ Array JSX
|
||||
}
|
||||
|
||||
rawContainer ∷ ∀ p. ReactComponent { | p }
|
||||
rawContainer =
|
||||
mkForwardRefComponent "InputContainer" do
|
||||
\(props ∷ { | PropsOptional }) ref -> React.do
|
||||
let
|
||||
result =
|
||||
M.div
|
||||
</* M.motion
|
||||
{ variants: M.variants containerVariants
|
||||
, animate: M.animate if props.hasFocus then containerVariantLabels.focussed else containerVariantLabels.blurred
|
||||
}
|
||||
{ className: "ry-input-container"
|
||||
, css: Style.inputContainer props
|
||||
, _data:
|
||||
props.isInvalid
|
||||
# foldMap \isInvalid ->
|
||||
Object.fromHomogeneous
|
||||
{ "invalid": show isInvalid
|
||||
}
|
||||
, ref
|
||||
}
|
||||
/> props.children
|
||||
pure result
|
||||
|
||||
drawPathUntil ∷ Int -> Array Point -> String
|
||||
drawPathUntil idx thePath = do
|
||||
let fn { x, y } = i x "%" " " y "%"
|
||||
let firstFew = Array.take idx thePath
|
||||
let lastFew = Array.drop idx thePath $> (Array.last firstFew # fromMaybe' \_ -> unsafeCrashWith "ogod")
|
||||
let rendered = intercalate "," $ fn <$> (firstFew <> lastFew)
|
||||
i "polygon(" rendered ")"
|
||||
|
||||
path ∷ Array Point
|
||||
path = mkPath 4 8
|
||||
|
||||
mkPath ∷ Int -> Int -> Array Point
|
||||
mkPath borderX borderY = do
|
||||
let
|
||||
inside =
|
||||
[ {- ⌜ -} p borderX borderY
|
||||
, {- ⌞ -} p borderX (100 - borderY)
|
||||
, {- ⌟ -} p (100 - borderX) (100 - borderY)
|
||||
, {- ⌝ -} p (100 - borderX) borderY
|
||||
, {- ⌜ -} p borderX borderY
|
||||
]
|
||||
outside =
|
||||
[ {-⌜ -} p 0 0
|
||||
, {-⌞ -} p 0 100
|
||||
, {- . -} p 25 100
|
||||
, {- . -} p 50 100
|
||||
, {- . -} p 75 100
|
||||
, {- ⌟-} p 100 100
|
||||
, {- ⌝-} p 100 0
|
||||
, {- ^ -} p 75 0
|
||||
, {- ^ -} p 50 0
|
||||
, {- ^ -} p 25 0
|
||||
, {-⌜ -} p 0 0
|
||||
]
|
||||
inside <> outside <> (Array.reverse inside)
|
||||
where
|
||||
p ∷ Int -> Int -> Point
|
||||
p x y = { x, y }
|
||||
|
||||
containerVariantLabels ∷
|
||||
{ blurred ∷ M.VariantLabel
|
||||
, focussed ∷ M.VariantLabel
|
||||
}
|
||||
containerVariantLabels = M.makeVariantLabels containerVariants
|
||||
|
||||
containerVariants ∷
|
||||
{ blurred ∷ CSS
|
||||
, focussed ∷ CSS
|
||||
}
|
||||
containerVariants =
|
||||
{ focussed:
|
||||
css
|
||||
{ clipPath
|
||||
, transition: { duration: 0.6 }
|
||||
}
|
||||
, blurred:
|
||||
css
|
||||
{ clipPath:
|
||||
drawPathUntil (Array.length path + 1) path
|
||||
}
|
||||
}
|
||||
where
|
||||
clipPath = 6 Array... (Array.length path) <#> \ln -> drawPathUntil ln path
|
||||
|
||||
type Point =
|
||||
{ x ∷ Int, y ∷ Int }
|
86
src/Yoga/Block/Atom/Input/View/Label.purs
Normal file
86
src/Yoga/Block/Atom/Input/View/Label.purs
Normal file
@ -0,0 +1,86 @@
|
||||
module Yoga.Block.Atom.Input.View.Label where
|
||||
|
||||
import Yoga.Prelude.View
|
||||
import Data.String.NonEmpty (NonEmptyString)
|
||||
import Data.String.NonEmpty as NonEmptyString
|
||||
import Effect.Unsafe (unsafePerformEffect)
|
||||
import Foreign.Object as Object
|
||||
import Framer.Motion as M
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.Hooks (reactComponent)
|
||||
import React.Basic.Hooks as React
|
||||
import Yoga.Block.Atom.Input.Style as Style
|
||||
|
||||
type Props =
|
||||
{ onClickLargeLabel ∷ EventHandler
|
||||
, isRequired ∷ Boolean
|
||||
, isInvalid ∷ Boolean
|
||||
, isFocussed ∷ Boolean
|
||||
, renderLargeLabel ∷ Boolean
|
||||
, leftIconRef ∷ NodeRef
|
||||
, inputRef ∷ NodeRef
|
||||
, labelId ∷ String
|
||||
, inputId ∷ String
|
||||
, labelText ∷ NonEmptyString
|
||||
}
|
||||
|
||||
component ∷ ReactComponent Props
|
||||
component =
|
||||
unsafePerformEffect
|
||||
$ reactComponent "Input Label" \props -> React.do
|
||||
-- Track input bounding box
|
||||
inputBbox /\ setInputBbox <- useState' (zero ∷ DOMRect)
|
||||
useEffectOnce do
|
||||
maybeBBox <- getBoundingBoxFromRef props.inputRef
|
||||
for_ maybeBBox setInputBbox
|
||||
mempty
|
||||
-- Left icon
|
||||
leftIconBbox /\ setLeftIconBbox <- useState' Nothing
|
||||
useEffectAlways do
|
||||
when (leftIconBbox == Nothing) do
|
||||
maybeBBox <- getBoundingBoxFromRef props.leftIconRef
|
||||
for_ maybeBBox (setLeftIconBbox <<< Just)
|
||||
mempty
|
||||
-- UI
|
||||
let
|
||||
result =
|
||||
container
|
||||
[ sharedLayout
|
||||
[ labelContainer
|
||||
[ labelSpan
|
||||
[ text ]
|
||||
]
|
||||
]
|
||||
]
|
||||
text = R.text $ NonEmptyString.toString props.labelText
|
||||
sharedLayout = M.animateSharedLayout </ { type: M.switch }
|
||||
container = div </* { className: "ry-input-label-container", css: Style.labelContainer }
|
||||
labelContainer =
|
||||
guard (inputBbox /= zero)
|
||||
$ M.div
|
||||
</* { className: if props.renderLargeLabel then "ry-input-label-large" else "ry-input-label-small"
|
||||
, layoutId: M.layoutId "ry-input-label"
|
||||
, css:
|
||||
if props.renderLargeLabel then
|
||||
Style.labelLarge { leftIconWidth: leftIconBbox <#> _.width, inputWidth: inputBbox.width }
|
||||
else
|
||||
Style.labelSmall
|
||||
, layout: M.layout true
|
||||
, transition: M.transition { duration: 0.18, ease: "easeOut" }
|
||||
, _data:
|
||||
Object.fromHomogeneous
|
||||
{ "has-focus": show props.isFocussed
|
||||
, "invalid": show props.isInvalid
|
||||
, "required": show props.isRequired
|
||||
}
|
||||
, initial: M.initial false
|
||||
}
|
||||
labelSpan =
|
||||
M.span
|
||||
</ { onClick: props.onClickLargeLabel
|
||||
, layout: M.layout true
|
||||
, layoutId: M.layoutId "ry-input-label-text"
|
||||
, htmlFor: props.inputId
|
||||
, id: props.labelId
|
||||
}
|
||||
pure result
|
@ -1,8 +1,9 @@
|
||||
module Yoga.Block.Layout.Cluster.Spec where
|
||||
|
||||
import Yoga.Prelude.Spec
|
||||
import Yoga.Block.Layout.Cluster as Cluster
|
||||
import Foreign.Object as Object
|
||||
import React.Basic.DOM as R
|
||||
import Yoga.Block.Layout.Cluster as Cluster
|
||||
|
||||
spec ∷ Spec Unit
|
||||
spec =
|
||||
@ -12,10 +13,11 @@ spec =
|
||||
void
|
||||
$ renderComponent Cluster.component {}
|
||||
it "accepts div props" do
|
||||
{ findByText } <-
|
||||
{ findByTestId } <-
|
||||
renderComponent Cluster.component
|
||||
{ role: "Heinz"
|
||||
, _data: Object.fromHomogeneous { testid: "cluster" }
|
||||
, children: [ R.text "Find me!" ]
|
||||
}
|
||||
elem <- findByText "Find me!"
|
||||
elem `shouldHaveAttribute` "role"
|
||||
elem <- findByTestId "cluster"
|
||||
shouldHaveAttributeWithValue elem "role" "Heinz"
|
||||
|
Loading…
Reference in New Issue
Block a user